Advertisement
Guest User

FastScroller2

a guest
Oct 31st, 2019
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 23.61 KB | None | 0 0
  1. /*
  2.  * Copyright 2018 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. /*
  18.  * NOTE: This is almost completely the same as FastScroller
  19.  * in the androidx.recycler.widget package. However, this one can
  20.  * account for the bottom padding, where the items are visible (clipToPadding="false"),
  21.  * but the fast scroller should not be inside the padded area (e. g. items visible
  22.  * behind a navigation bar, but the scroller should not go under the navigation bar).
  23.  */
  24.  
  25. package com.lb.myapplication;
  26.  
  27. import android.animation.Animator;
  28. import android.animation.AnimatorListenerAdapter;
  29. import android.animation.ValueAnimator;
  30. import android.animation.ValueAnimator.AnimatorUpdateListener;
  31. import android.graphics.Canvas;
  32. import android.graphics.drawable.Drawable;
  33. import android.graphics.drawable.StateListDrawable;
  34. import android.view.MotionEvent;
  35.  
  36. import androidx.annotation.IntDef;
  37. import androidx.annotation.NonNull;
  38. import androidx.annotation.Nullable;
  39. import androidx.annotation.VisibleForTesting;
  40. import androidx.core.view.ViewCompat;
  41. import androidx.recyclerview.widget.RecyclerView;
  42.  
  43. import java.lang.annotation.Retention;
  44. import java.lang.annotation.RetentionPolicy;
  45.  
  46. /**
  47.  * Class responsible to animate and provide a fast scroller.
  48.  */
  49.  
  50. class FastScroller2 extends RecyclerView.ItemDecoration implements RecyclerView.OnItemTouchListener {
  51.     @IntDef({STATE_HIDDEN, STATE_VISIBLE, STATE_DRAGGING})
  52.     @Retention(RetentionPolicy.SOURCE)
  53.     private @interface State { }
  54.     // Scroll thumb not showing
  55.     private static final int STATE_HIDDEN = 0;
  56.     // Scroll thumb visible and moving along with the scrollbar
  57.     private static final int STATE_VISIBLE = 1;
  58.     // Scroll thumb being dragged by user
  59.     private static final int STATE_DRAGGING = 2;
  60.  
  61.     @IntDef({DRAG_X, DRAG_Y, DRAG_NONE})
  62.     @Retention(RetentionPolicy.SOURCE)
  63.     private @interface DragState{ }
  64.     private static final int DRAG_NONE = 0;
  65.     private static final int DRAG_X = 1;
  66.     private static final int DRAG_Y = 2;
  67.  
  68.     @IntDef({ANIMATION_STATE_OUT, ANIMATION_STATE_FADING_IN, ANIMATION_STATE_IN,
  69.             ANIMATION_STATE_FADING_OUT})
  70.     @Retention(RetentionPolicy.SOURCE)
  71.     private @interface AnimationState { }
  72.     private static final int ANIMATION_STATE_OUT = 0;
  73.     private static final int ANIMATION_STATE_FADING_IN = 1;
  74.     private static final int ANIMATION_STATE_IN = 2;
  75.     private static final int ANIMATION_STATE_FADING_OUT = 3;
  76.  
  77.     private static final int SHOW_DURATION_MS = 500;
  78.     private static final int HIDE_DELAY_AFTER_VISIBLE_MS = 1500;
  79.     private static final int HIDE_DELAY_AFTER_DRAGGING_MS = 1200;
  80.     private static final int HIDE_DURATION_MS = 500;
  81.     private static final int SCROLLBAR_FULL_OPAQUE = 255;
  82.  
  83.     private static final int[] PRESSED_STATE_SET = new int[]{android.R.attr.state_pressed};
  84.     private static final int[] EMPTY_STATE_SET = new int[]{};
  85.  
  86.     private final int mScrollbarMinimumRange;
  87.     private final int mMargin;
  88.  
  89.     // Final values for the vertical scroll bar
  90.     @SuppressWarnings("WeakerAccess") /* synthetic access */
  91.     final StateListDrawable mVerticalThumbDrawable;
  92.     @SuppressWarnings("WeakerAccess") /* synthetic access */
  93.     final Drawable mVerticalTrackDrawable;
  94.     private final int mVerticalThumbWidth;
  95.     private final int mVerticalTrackWidth;
  96.     private final boolean mConsiderPadding;
  97.  
  98.     // Final values for the horizontal scroll bar
  99.     private final StateListDrawable mHorizontalThumbDrawable;
  100.     private final Drawable mHorizontalTrackDrawable;
  101.     private final int mHorizontalThumbHeight;
  102.     private final int mHorizontalTrackHeight;
  103.  
  104.     // Dynamic values for the vertical scroll bar
  105.     @VisibleForTesting int mVerticalThumbHeight;
  106.     @VisibleForTesting int mVerticalThumbCenterY;
  107.     @VisibleForTesting float mVerticalDragY;
  108.  
  109.     // Dynamic values for the horizontal scroll bar
  110.     @VisibleForTesting int mHorizontalThumbWidth;
  111.     @VisibleForTesting int mHorizontalThumbCenterX;
  112.     @VisibleForTesting float mHorizontalDragX;
  113.  
  114.     private int mRecyclerViewWidth = 0;
  115.     private int mRecyclerViewHeight = 0;
  116.  
  117.     private RecyclerView mRecyclerView;
  118.     /**
  119.      * Whether the document is long/wide enough to require scrolling. If not, we don't show the
  120.      * relevant scroller.
  121.      */
  122.     private boolean mNeedVerticalScrollbar = false;
  123.     private boolean mNeedHorizontalScrollbar = false;
  124.     @State private int mState = STATE_HIDDEN;
  125.     @DragState private int mDragState = DRAG_NONE;
  126.  
  127.     private final int[] mVerticalRange = new int[2];
  128.     private final int[] mHorizontalRange = new int[2];
  129.     @SuppressWarnings("WeakerAccess") /* synthetic access */
  130.     final ValueAnimator mShowHideAnimator = ValueAnimator.ofFloat(0, 1);
  131.     @SuppressWarnings("WeakerAccess") /* synthetic access */
  132.     @AnimationState int mAnimationState = ANIMATION_STATE_OUT;
  133.     private final Runnable mHideRunnable = new Runnable() {
  134.         @Override
  135.         public void run() {
  136.             hide(HIDE_DURATION_MS);
  137.         }
  138.     };
  139.     private final RecyclerView.OnScrollListener
  140.             mOnScrollListener = new RecyclerView.OnScrollListener() {
  141.         @Override
  142.         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
  143.             updateScrollPosition(recyclerView.computeHorizontalScrollOffset(),
  144.                     recyclerView.computeVerticalScrollOffset());
  145.         }
  146.     };
  147.  
  148.     FastScroller2(RecyclerView recyclerView, StateListDrawable verticalThumbDrawable,
  149.                   Drawable verticalTrackDrawable, StateListDrawable horizontalThumbDrawable,
  150.                   Drawable horizontalTrackDrawable, int defaultWidth, int scrollbarMinimumRange,
  151.                   int margin, boolean considerPadding) {
  152.         mVerticalThumbDrawable = verticalThumbDrawable;
  153.         mVerticalTrackDrawable = verticalTrackDrawable;
  154.         mHorizontalThumbDrawable = horizontalThumbDrawable;
  155.         mHorizontalTrackDrawable = horizontalTrackDrawable;
  156.         mVerticalThumbWidth = Math.max(defaultWidth, verticalThumbDrawable.getIntrinsicWidth());
  157.         mVerticalTrackWidth = Math.max(defaultWidth, verticalTrackDrawable.getIntrinsicWidth());
  158.         mHorizontalThumbHeight = Math
  159.                 .max(defaultWidth, horizontalThumbDrawable.getIntrinsicWidth());
  160.         mHorizontalTrackHeight = Math
  161.                 .max(defaultWidth, horizontalTrackDrawable.getIntrinsicWidth());
  162.         mScrollbarMinimumRange = scrollbarMinimumRange;
  163.         mMargin = margin;
  164.         mVerticalThumbDrawable.setAlpha(SCROLLBAR_FULL_OPAQUE);
  165.         mVerticalTrackDrawable.setAlpha(SCROLLBAR_FULL_OPAQUE);
  166.         mConsiderPadding = considerPadding;
  167.  
  168.         mShowHideAnimator.addListener(new AnimatorListener());
  169.         mShowHideAnimator.addUpdateListener(new AnimatorUpdater());
  170.  
  171.         attachToRecyclerView(recyclerView);
  172.     }
  173.  
  174.     public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
  175.         if (mRecyclerView == recyclerView) {
  176.             return; // nothing to do
  177.         }
  178.         if (mRecyclerView != null) {
  179.             destroyCallbacks();
  180.         }
  181.         mRecyclerView = recyclerView;
  182.         if (mRecyclerView != null) {
  183.             setupCallbacks();
  184.         }
  185.     }
  186.  
  187.     private void setupCallbacks() {
  188.         mRecyclerView.addItemDecoration(this);
  189.         mRecyclerView.addOnItemTouchListener(this);
  190.         mRecyclerView.addOnScrollListener(mOnScrollListener);
  191.     }
  192.  
  193.     private void destroyCallbacks() {
  194.         mRecyclerView.removeItemDecoration(this);
  195.         mRecyclerView.removeOnItemTouchListener(this);
  196.         mRecyclerView.removeOnScrollListener(mOnScrollListener);
  197.         cancelHide();
  198.     }
  199.  
  200.     @SuppressWarnings("WeakerAccess") /* synthetic access */
  201.     void requestRedraw() {
  202.         mRecyclerView.invalidate();
  203.     }
  204.  
  205.     void setState(@State int state) {
  206.         if (state == STATE_DRAGGING && mState != STATE_DRAGGING) {
  207.             mVerticalThumbDrawable.setState(PRESSED_STATE_SET);
  208.             cancelHide();
  209.         }
  210.  
  211.         if (state == STATE_HIDDEN) {
  212.             requestRedraw();
  213.         } else {
  214.             show();
  215.         }
  216.  
  217.         if (mState == STATE_DRAGGING && state != STATE_DRAGGING) {
  218.             mVerticalThumbDrawable.setState(EMPTY_STATE_SET);
  219.             resetHideDelay(HIDE_DELAY_AFTER_DRAGGING_MS);
  220.         } else if (state == STATE_VISIBLE) {
  221.             resetHideDelay(HIDE_DELAY_AFTER_VISIBLE_MS);
  222.         }
  223.         mState = state;
  224.     }
  225.  
  226.     private boolean isLayoutRTL() {
  227.         return ViewCompat.getLayoutDirection(mRecyclerView) == ViewCompat.LAYOUT_DIRECTION_RTL;
  228.     }
  229.  
  230.     public boolean isDragging() {
  231.         return mState == STATE_DRAGGING;
  232.     }
  233.  
  234.     @VisibleForTesting boolean isVisible() {
  235.         return mState == STATE_VISIBLE;
  236.     }
  237.  
  238.     public void show() {
  239.         switch (mAnimationState) {
  240.             case ANIMATION_STATE_FADING_OUT:
  241.                 mShowHideAnimator.cancel();
  242.                 // fall through
  243.             case ANIMATION_STATE_OUT:
  244.                 mAnimationState = ANIMATION_STATE_FADING_IN;
  245.                 mShowHideAnimator.setFloatValues((float) mShowHideAnimator.getAnimatedValue(), 1);
  246.                 mShowHideAnimator.setDuration(SHOW_DURATION_MS);
  247.                 mShowHideAnimator.setStartDelay(0);
  248.                 mShowHideAnimator.start();
  249.                 break;
  250.         }
  251.     }
  252.  
  253.     @VisibleForTesting
  254.     void hide(int duration) {
  255.         switch (mAnimationState) {
  256.             case ANIMATION_STATE_FADING_IN:
  257.                 mShowHideAnimator.cancel();
  258.                 // fall through
  259.             case ANIMATION_STATE_IN:
  260.                 mAnimationState = ANIMATION_STATE_FADING_OUT;
  261.                 mShowHideAnimator.setFloatValues((float) mShowHideAnimator.getAnimatedValue(), 0);
  262.                 mShowHideAnimator.setDuration(duration);
  263.                 mShowHideAnimator.start();
  264.                 break;
  265.         }
  266.     }
  267.  
  268.     private void cancelHide() {
  269.         mRecyclerView.removeCallbacks(mHideRunnable);
  270.     }
  271.  
  272.     private void resetHideDelay(int delay) {
  273.         cancelHide();
  274.         mRecyclerView.postDelayed(mHideRunnable, delay);
  275.     }
  276.  
  277.     @Override
  278.     public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
  279.         if (mRecyclerViewWidth != mRecyclerView.getWidth()
  280.                 || mRecyclerViewHeight != mRecyclerView.getHeight()) {
  281.             mRecyclerViewWidth = mRecyclerView.getWidth();
  282.             mRecyclerViewHeight = mRecyclerView.getHeight();
  283.             // This is due to the different events ordering when keyboard is opened or
  284.             // retracted vs rotate. Hence to avoid corner cases we just disable the
  285.             // scroller when size changed, and wait until the scroll position is recomputed
  286.             // before showing it back.
  287.             setState(STATE_HIDDEN);
  288.             return;
  289.         }
  290.  
  291.         if (mAnimationState != ANIMATION_STATE_OUT) {
  292.             if (mNeedVerticalScrollbar) {
  293.                 drawVerticalScrollbar(canvas);
  294.             }
  295.             if (mNeedHorizontalScrollbar) {
  296.                 drawHorizontalScrollbar(canvas);
  297.             }
  298.         }
  299.     }
  300.  
  301.     private void drawVerticalScrollbar(Canvas canvas) {
  302.         int viewWidth = mRecyclerViewWidth;
  303.  
  304.         int left = viewWidth - mVerticalThumbWidth;
  305.         // Counter intuitive, but left and right are switched here
  306.         if (mConsiderPadding) left -= mRecyclerView.getPaddingRight();
  307.         int top = mVerticalThumbCenterY - mVerticalThumbHeight / 2;
  308.         mVerticalThumbDrawable.setBounds(0, 0, mVerticalThumbWidth, mVerticalThumbHeight);
  309.         int trackTop = 0;
  310.         int trackBottom = mRecyclerViewHeight;
  311.         if (mConsiderPadding) trackBottom -= mRecyclerView.getPaddingBottom();
  312.         mVerticalTrackDrawable
  313.                 .setBounds(0, trackTop, mVerticalTrackWidth, trackBottom);
  314.  
  315.         if (isLayoutRTL()) {
  316.             mVerticalTrackDrawable.draw(canvas);
  317.             canvas.translate(mVerticalThumbWidth, top);
  318.             canvas.scale(-1, 1);
  319.             mVerticalThumbDrawable.draw(canvas);
  320.             canvas.scale(1, 1);
  321.             canvas.translate(-mVerticalThumbWidth, -top);
  322.         } else {
  323.             canvas.translate(left, 0);
  324.             mVerticalTrackDrawable.draw(canvas);
  325.             canvas.translate(0, top);
  326.             mVerticalThumbDrawable.draw(canvas);
  327.             canvas.translate(-left, -top);
  328.         }
  329.     }
  330.  
  331.     private void drawHorizontalScrollbar(Canvas canvas) {
  332.         int viewHeight = mRecyclerViewHeight;
  333.  
  334.         int top = viewHeight - mHorizontalThumbHeight;
  335.         int left = mHorizontalThumbCenterX - mHorizontalThumbWidth / 2;
  336.         mHorizontalThumbDrawable.setBounds(0, 0, mHorizontalThumbWidth, mHorizontalThumbHeight);
  337.         mHorizontalTrackDrawable
  338.                 .setBounds(0, 0, mRecyclerViewWidth, mHorizontalTrackHeight);
  339.  
  340.         canvas.translate(0, top);
  341.         mHorizontalTrackDrawable.draw(canvas);
  342.         canvas.translate(left, 0);
  343.         mHorizontalThumbDrawable.draw(canvas);
  344.         canvas.translate(-left, -top);
  345.     }
  346.  
  347.     /**
  348.      * Notify the scroller of external change of the scroll, e.g. through dragging or flinging on
  349.      * the view itself.
  350.      *
  351.      * @param offsetX The new scroll X offset.
  352.      * @param offsetY The new scroll Y offset.
  353.      */
  354.     void updateScrollPosition(int offsetX, int offsetY) {
  355.         int verticalContentLength = mRecyclerView.computeVerticalScrollRange();
  356.         int verticalVisibleLength = mRecyclerViewHeight;
  357.         // This is important, because the thumb is drawn inside the vertical visible length!
  358.         if (mConsiderPadding) verticalVisibleLength -= mRecyclerView.getPaddingBottom();
  359.         mNeedVerticalScrollbar = verticalContentLength - verticalVisibleLength > 0
  360.                 && mRecyclerViewHeight >= mScrollbarMinimumRange;
  361.  
  362.         int horizontalContentLength = mRecyclerView.computeHorizontalScrollRange();
  363.         int horizontalVisibleLength = mRecyclerViewWidth;
  364.         mNeedHorizontalScrollbar = horizontalContentLength - horizontalVisibleLength > 0
  365.                 && mRecyclerViewWidth >= mScrollbarMinimumRange;
  366.  
  367.         if (!mNeedVerticalScrollbar && !mNeedHorizontalScrollbar) {
  368.             if (mState != STATE_HIDDEN) {
  369.                 setState(STATE_HIDDEN);
  370.             }
  371.             return;
  372.         }
  373.  
  374.         if (mNeedVerticalScrollbar) {
  375.             float middleScreenPos = offsetY + verticalVisibleLength / 2.0f;
  376.             mVerticalThumbCenterY =
  377.                     (int) ((verticalVisibleLength * middleScreenPos) / verticalContentLength);
  378.             mVerticalThumbHeight = Math.min(verticalVisibleLength,
  379.                     (verticalVisibleLength * verticalVisibleLength) / verticalContentLength);
  380.         }
  381.  
  382.         if (mNeedHorizontalScrollbar) {
  383.             float middleScreenPos = offsetX + horizontalVisibleLength / 2.0f;
  384.             mHorizontalThumbCenterX =
  385.                     (int) ((horizontalVisibleLength * middleScreenPos) / horizontalContentLength);
  386.             mHorizontalThumbWidth = Math.min(horizontalVisibleLength,
  387.                     (horizontalVisibleLength * horizontalVisibleLength) / horizontalContentLength);
  388.         }
  389.  
  390.         if (mState == STATE_HIDDEN || mState == STATE_VISIBLE) {
  391.             setState(STATE_VISIBLE);
  392.         }
  393.     }
  394.  
  395.     @Override
  396.     public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
  397.                                          @NonNull MotionEvent ev) {
  398.         final boolean handled;
  399.         if (mState == STATE_VISIBLE) {
  400.             boolean insideVerticalThumb = isPointInsideVerticalThumb(ev.getX(), ev.getY());
  401.             boolean insideHorizontalThumb = isPointInsideHorizontalThumb(ev.getX(), ev.getY());
  402.             if (ev.getAction() == MotionEvent.ACTION_DOWN
  403.                     && (insideVerticalThumb || insideHorizontalThumb)) {
  404.                 if (insideHorizontalThumb) {
  405.                     mDragState = DRAG_X;
  406.                     mHorizontalDragX = (int) ev.getX();
  407.                 } else if (insideVerticalThumb) {
  408.                     mDragState = DRAG_Y;
  409.                     mVerticalDragY = (int) ev.getY();
  410.                 }
  411.  
  412.                 setState(STATE_DRAGGING);
  413.                 handled = true;
  414.             } else {
  415.                 handled = false;
  416.             }
  417.         } else if (mState == STATE_DRAGGING) {
  418.             handled = true;
  419.         } else {
  420.             handled = false;
  421.         }
  422.         return handled;
  423.     }
  424.  
  425.     @Override
  426.     public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent me) {
  427.         if (mState == STATE_HIDDEN) {
  428.             return;
  429.         }
  430.  
  431.         if (me.getAction() == MotionEvent.ACTION_DOWN) {
  432.             boolean insideVerticalThumb = isPointInsideVerticalThumb(me.getX(), me.getY());
  433.             boolean insideHorizontalThumb = isPointInsideHorizontalThumb(me.getX(), me.getY());
  434.             if (insideVerticalThumb || insideHorizontalThumb) {
  435.                 if (insideHorizontalThumb) {
  436.                     mDragState = DRAG_X;
  437.                     mHorizontalDragX = (int) me.getX();
  438.                 } else if (insideVerticalThumb) {
  439.                     mDragState = DRAG_Y;
  440.                     mVerticalDragY = (int) me.getY();
  441.                 }
  442.                 setState(STATE_DRAGGING);
  443.             }
  444.         } else if (me.getAction() == MotionEvent.ACTION_UP && mState == STATE_DRAGGING) {
  445.             mVerticalDragY = 0;
  446.             mHorizontalDragX = 0;
  447.             setState(STATE_VISIBLE);
  448.             mDragState = DRAG_NONE;
  449.         } else if (me.getAction() == MotionEvent.ACTION_MOVE && mState == STATE_DRAGGING) {
  450.             show();
  451.             if (mDragState == DRAG_X) {
  452.                 horizontalScrollTo(me.getX());
  453.             }
  454.             if (mDragState == DRAG_Y) {
  455.                 verticalScrollTo(me.getY());
  456.             }
  457.         }
  458.     }
  459.  
  460.     @Override
  461.     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
  462.  
  463.     private void verticalScrollTo(float y) {
  464.         final int[] scrollbarRange = getVerticalRange();
  465.         // We want to allow the user to scroll over the bounds.
  466.         // y = Math.max(scrollbarRange[0], Math.min(scrollbarRange[1], y));
  467.         if (Math.abs(mVerticalThumbCenterY - y) < 2) {
  468.             return;
  469.         }
  470.         int height = mRecyclerViewHeight;
  471.         if (mConsiderPadding) height -= mRecyclerView.getPaddingBottom();
  472.         int scrollingBy = scrollTo(mVerticalDragY, y, scrollbarRange,
  473.                 mRecyclerView.computeVerticalScrollRange(),
  474.                 mRecyclerView.computeVerticalScrollOffset(), height);
  475.         if (scrollingBy != 0) {
  476.             mRecyclerView.scrollBy(0, scrollingBy);
  477.         }
  478.         mVerticalDragY = y;
  479.     }
  480.  
  481.     private void horizontalScrollTo(float x) {
  482.         final int[] scrollbarRange = getHorizontalRange();
  483.         x = Math.max(scrollbarRange[0], Math.min(scrollbarRange[1], x));
  484.         if (Math.abs(mHorizontalThumbCenterX - x) < 2) {
  485.             return;
  486.         }
  487.  
  488.         int scrollingBy = scrollTo(mHorizontalDragX, x, scrollbarRange,
  489.                 mRecyclerView.computeHorizontalScrollRange(),
  490.                 mRecyclerView.computeHorizontalScrollOffset(), mRecyclerViewWidth);
  491.         if (scrollingBy != 0) {
  492.             mRecyclerView.scrollBy(scrollingBy, 0);
  493.         }
  494.  
  495.         mHorizontalDragX = x;
  496.     }
  497.  
  498.     private int scrollTo(float oldDragPos, float newDragPos, int[] scrollbarRange, int scrollRange,
  499.                          int scrollOffset, int viewLength) {
  500.         int scrollbarLength = scrollbarRange[1] - scrollbarRange[0];
  501.         if (scrollbarLength == 0) {
  502.             return 0;
  503.         }
  504.         float percentage = ((newDragPos - oldDragPos) / (float) scrollbarLength);
  505.         int totalPossibleOffset = scrollRange - viewLength;
  506.         int scrollingBy = (int) (percentage * totalPossibleOffset);
  507.         int absoluteOffset = scrollOffset + scrollingBy;
  508.         if (absoluteOffset < totalPossibleOffset && absoluteOffset >= 0) {
  509.             return scrollingBy;
  510.         } else {
  511.             return 0;
  512.         }
  513.     }
  514.  
  515.     @VisibleForTesting
  516.     boolean isPointInsideVerticalThumb(float x, float y) {
  517.         return (isLayoutRTL() ? x <= mVerticalThumbWidth / 2
  518.                 : x >= mRecyclerViewWidth - mVerticalThumbWidth)
  519.                 && y >= mVerticalThumbCenterY - mVerticalThumbHeight / 2
  520.                 && y <= mVerticalThumbCenterY + mVerticalThumbHeight / 2;
  521.     }
  522.  
  523.     @VisibleForTesting
  524.     boolean isPointInsideHorizontalThumb(float x, float y) {
  525.         return (y >= mRecyclerViewHeight - mHorizontalThumbHeight)
  526.                 && x >= mHorizontalThumbCenterX - mHorizontalThumbWidth / 2
  527.                 && x <= mHorizontalThumbCenterX + mHorizontalThumbWidth / 2;
  528.     }
  529.  
  530.     @VisibleForTesting
  531.     Drawable getHorizontalTrackDrawable() {
  532.         return mHorizontalTrackDrawable;
  533.     }
  534.  
  535.     @VisibleForTesting
  536.     Drawable getHorizontalThumbDrawable() {
  537.         return mHorizontalThumbDrawable;
  538.     }
  539.  
  540.     @VisibleForTesting
  541.     Drawable getVerticalTrackDrawable() {
  542.         return mVerticalTrackDrawable;
  543.     }
  544.  
  545.     @VisibleForTesting
  546.     Drawable getVerticalThumbDrawable() {
  547.         return mVerticalThumbDrawable;
  548.     }
  549.  
  550.     /**
  551.      * Gets the (min, max) vertical positions of the vertical scroll bar.
  552.      */
  553.     private int[] getVerticalRange() {
  554.         mVerticalRange[0] = mMargin;
  555.         mVerticalRange[1] = mRecyclerViewHeight - mMargin;
  556.         if (mConsiderPadding) mVerticalRange[1] -= mRecyclerView.getPaddingBottom();
  557.         return mVerticalRange;
  558.     }
  559.  
  560.     /**
  561.      * Gets the (min, max) horizontal positions of the horizontal scroll bar.
  562.      */
  563.     private int[] getHorizontalRange() {
  564.         mHorizontalRange[0] = mMargin;
  565.         mHorizontalRange[1] = mRecyclerViewWidth - mMargin;
  566.         return mHorizontalRange;
  567.     }
  568.  
  569.     private class AnimatorListener extends AnimatorListenerAdapter {
  570.  
  571.         private boolean mCanceled = false;
  572.  
  573.         AnimatorListener() {
  574.         }
  575.  
  576.         @Override
  577.         public void onAnimationEnd(Animator animation) {
  578.             // Cancel is always followed by a new directive, so don't update state.
  579.             if (mCanceled) {
  580.                 mCanceled = false;
  581.                 return;
  582.             }
  583.             if ((float) mShowHideAnimator.getAnimatedValue() == 0) {
  584.                 mAnimationState = ANIMATION_STATE_OUT;
  585.                 setState(STATE_HIDDEN);
  586.             } else {
  587.                 mAnimationState = ANIMATION_STATE_IN;
  588.                 requestRedraw();
  589.             }
  590.         }
  591.  
  592.         @Override
  593.         public void onAnimationCancel(Animator animation) {
  594.             mCanceled = true;
  595.         }
  596.     }
  597.  
  598.     private class AnimatorUpdater implements AnimatorUpdateListener {
  599.         AnimatorUpdater() {
  600.         }
  601.  
  602.         @Override
  603.         public void onAnimationUpdate(ValueAnimator valueAnimator) {
  604.             int alpha = (int) (SCROLLBAR_FULL_OPAQUE * ((float) valueAnimator.getAnimatedValue()));
  605.             mVerticalThumbDrawable.setAlpha(alpha);
  606.             mVerticalTrackDrawable.setAlpha(alpha);
  607.             requestRedraw();
  608.         }
  609.     }
  610. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement