title: How to have the proper vertical scroll range, but make the physical size of the track different?
body: <p><strong>EDIT (2/3/22):</strong> Based on what I have here, I was thinking about changing this custom RecyclerView into a scrollbar class, with all scrolling bits in one layout imported into each view and then feeding the view to the class. My idea with this is to try and make the track height fixed, and then use the values provided by the view to then set the thumb length according to both the view contents <em>and</em> the fact that the track itself is a fixed height. Any thoughts or comments would be greatly appreciated.</p>
  <p>I've been working with a custom class in order to change the scrollbar and how it looks. With some research, I managed to set up this scrollbarRecyclerView class using an article I found discussing specifically thumb length customization:</p>
  <pre><code>public final class scrollbarRecyclerView extends RecyclerView implements ScrollingView {
  public int thumbLength;
  public int trackLength;
  private int totalLength;
  
  public final int getThumbLength() {
      return this.thumbLength;
  }
  public final void setThumbLength(int value) {
      this.thumbLength = value;
  }
  
  public final int getTrackLength() {
      return this.trackLength;
  }
  public final void setTrackLength(int value) {
      this.trackLength = value;
  }
  
  public int computeHorizontalScrollRange() {
      if (this.trackLength == -1) {
          this.trackLength = this.getMeasuredWidth();
      }
  
      return this.trackLength;
  }
  
  public int computeHorizontalScrollOffset() {
      this.getWidth();
      int highestVisiblePixel = super.computeHorizontalScrollOffset();
      return this.computeScrollOffset(highestVisiblePixel);
  }
  
  public int computeHorizontalScrollExtent() {
      return this.thumbLength;
  }
  
  public int computeVerticalScrollRange() {
      if (this.trackLength == -1) {
          this.trackLength = this.getMeasuredHeight();
      }
  
      return this.trackLength;
  }
  
  public int computeVerticalScrollOffset() {
      this.getHeight();
      int highestVisiblePixel = super.computeVerticalScrollOffset();
      return this.computeScrollOffset(highestVisiblePixel);
  }
  
  private final int computeScrollOffset(int highestVisiblePixel) {
      int invisiblePartOfRecyclerView = this.totalLength - this.trackLength;
      int scrollAmountRemaining = invisiblePartOfRecyclerView - highestVisiblePixel;
      return invisiblePartOfRecyclerView == scrollAmountRemaining ? 0 : (scrollAmountRemaining &gt; 0 ? MathKt.roundToInt((float) (this.trackLength - this.thumbLength) / ((float) invisiblePartOfRecyclerView / (float) highestVisiblePixel)) : this.trackLength - this.thumbLength);
  }
  
  public int computeVerticalScrollExtent() {
      return this.thumbLength;
  }
  
  private final void getHeight() {
      if (this.totalLength == -1) {
          int normalHeight = this.getMeasuredHeight();
          this.trackLength = normalHeight;
          this.measure(MeasureSpec.makeMeasureSpec(this.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
          this.totalLength = this.getMeasuredHeight();
          this.measure(MeasureSpec.makeMeasureSpec(this.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(normalHeight, MeasureSpec.AT_MOST));
      }
  
  }
  
  private final void getWidth() {
      if (this.totalLength == -1) {
          int normalWidth = this.getMeasuredWidth();
          this.trackLength = normalWidth;
          this.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(this.getMeasuredHeight(), MeasureSpec.EXACTLY));
          this.totalLength = this.getMeasuredWidth();
          this.measure(MeasureSpec.makeMeasureSpec(normalWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(this.getMeasuredHeight(), MeasureSpec.AT_MOST));
      }
  
  }
  
  public final int dpToPx(int dp) {
      float var10000 = (float) dp;
      Resources var10001 = this.getResources();
      Intrinsics.checkNotNullExpressionValue(var10001, &quot;resources&quot;);
      return MathKt.roundToInt(var10000 * var10001.getDisplayMetrics().density);
  }
  
  public scrollbarRecyclerView(@NotNull Context context, @Nullable AttributeSet attrs) {
      super(context, attrs);
      Intrinsics.checkNotNullParameter(context, &quot;context&quot;);
      this.trackLength = -1;
      this.totalLength = -1;
      TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.scrollbarRecyclerView);
      this.thumbLength = this.dpToPx((int) typedArray.getDimension(R.styleable.scrollbarRecyclerView_thumbLength, 64.0F));
      this.trackLength = this.dpToPx((int) typedArray.getDimension(R.styleable.scrollbarRecyclerView_trackLength, 128.0F));
      typedArray.recycle();
  }
  
  public scrollbarRecyclerView(@NotNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      Intrinsics.checkNotNullParameter(context, &quot;context&quot;);
      this.trackLength = -1;
      this.totalLength = -1;
      TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.scrollbarRecyclerView);
      this.thumbLength = this.dpToPx((int) typedArray.getDimension(R.styleable.scrollbarRecyclerView_thumbLength, 64.0F));
      this.trackLength = this.dpToPx((int) typedArray.getDimension(R.styleable.scrollbarRecyclerView_trackLength, 128.0F));
      typedArray.recycle();
  }
  }
  </code></pre>
  <p>attrs.xml file with thumbLength dimension defined:</p>
  <pre><code>&lt;resources&gt;
     &lt;declare-styleable name=&quot;scrollbarRecyclerView&quot;&gt;
         &lt;attr name=&quot;thumbLength&quot; format=&quot;dimension&quot; /&gt;
         &lt;attr name=&quot;trackLength&quot; format=&quot;dimension&quot; /&gt;
     &lt;/declare-styleable&gt;
  &lt;/resources&gt;
  </code></pre>
  <p>Reference to the article in question (written in Kotlin; I rewrote it in Java for my purposes): <a href="https://coffeecode97.medium.com/recyclerview-custom-thumb-size-length-136f1836af9c" rel="nofollow noreferrer">https://coffeecode97.medium.com/recyclerview-custom-thumb-size-length-136f1836af9c</a></p>
  <p>As-is, this will draw the scrollbar track itself normally, but allows (with an attrs.xml value) the thumbLength to be customized and still remain accurate (with this custom RecyclerView, I can make the thumb as large or as small as I want, and when scrolled, it's perfectly accurate).</p>
  <p>However, while this is useful, it doesn't seem to allow me to do the same with the track itself. I tried adding trackLength values to the constructors and attrs.xml file in order to try and modify the height of the track just like the thumb, but it's not possible. The setter also doesn't affect it (calling scrollbarRecyclerView.setTrackLength(val) in the class I'm using it in). Looking at the computeVerticalScrollRange() and getHeight() methods, it seems like the track's length is solely defined/modified by these. However, even modifying these to try and make the track height different doesn't seem to have any affect, either. Does anyone know what I'm missing in order to modify the size of the track as easily as the thumb?</p>