scroll associated methods and properties Android View flexible slip principle Scroller

In a recent modification fragmentation of the bug, which SwipeBackLayout is implemented using ViewDragHelper, and ViewDragHelper using OverScroller, OverScroller in most of the time it can replace the Scroller. So start with the Scroller to analyze this knowledge be used several times, often forget, are also considered to be a note.

Android development, but in the actual use of these api, developers can easily lead to confusion in the moving direction, moving distance, this paper summarizes the difference between legend and contact these four methods.

Many articles in the flexible slip Scroller time, often view the method and the method Scroller class, mixed together, for ease of understanding, the method will be described below a method and scroll separation View class Scroller

A, View of scroll-related methods

Note The following methods are methods View

In the custom of the time, if it comes to slip event, often you need to use such scrollTo View offer (), scrollBy (), getScrollX (), getScrollY () methods.

Slide Objects

and a content slide scrollTo scrollBy View, rather than changing the position in which the View itself. So, separate View slide is rare, more of a call to scroll ViewGroup child controls the position of the sliding method. For example, the use of TextView object to call scrollTo or ScrollBy method, you will find the location of the text inside the TextView change, and the position in which the TextView itself has not changed, that is to say Textview click event position has not changed. (View animation, change its position on, read this article )

    /**
     * Return the scrolled left position of this view. This is the left edge of
     * the displayed part of your view. You do not need to draw any pixels
     * farther left, since those are outside of the frame of your view on
     * screen.
     *
     * @return The left edge of the displayed part of your view, in pixels.
     */
    public final int getScrollX() {
        return mScrollX;
    }

    /**
     * Return the scrolled top position of this view. This is the top edge of
     * the displayed part of your view. You do not need to draw any pixels above
     * it, since those are outside of the frame of your view on screen.
     *
     * @return The top edge of the displayed part of your view, in pixels.
     */
    public final int getScrollY() {
        return mScrollY;
    }

getScrollX () and getScrollY ()

Return Value mScrollX and mScrollY respectively represent an offset in the X-axis or Y-axis directions from the starting position View, View coordinate values ​​rather than on the X-axis or Y-axis direction, for recording two offset increments variable. Therefore, the initial values ​​mScrollY mScrollX and 0 and 0.

    /**
     * Set the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the x position to scroll to
     * @param y the y position to scroll to
     */
   参数 x,y,表示要移动到的位置,赋值给mScrollX和mScrollY
   比如,我想移动到(100,100)这个位置,那么偏移量就是(0,0-100,100=-100100),所以调用的时候就是view.scrollTo(-100, -100),这样才能达到我们想要的偏移效果。
   这个方法,已经能够实现view的位置移动,看上去是一瞬间完成的,没有动画效果。
   
    public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

    /**
     * Move the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the amount of pixels to scroll by horizontally
     * @param y the amount of pixels to scroll by vertically
     */
     
    参数 x,y,表示相对于mScrollX和mScrollY要移动的偏移量,
    public void scrollBy(int x, int y) {
        // scrollBy实际是调用了scrollTo方法:scrollTo(mScrollX + x, mScrollY + y)
        scrollTo(mScrollX + x, mScrollY + y);
    }

Relationship between positive and negative values ​​and direction of movement of the reference picture below, is to find online map
Here Insert Picture Description

    /**
     * Called by a parent to request that a child update its values for mScrollX
     * and mScrollY if necessary. This will typically be done if the child is
     * animating a scroll using a {@link android.widget.Scroller Scroller}
     * object.
     */
    public void computeScroll() {
    }

computeScroll

View of computeScroll () method is null, the annotation of view, this method is designed to fit Scroller, move to achieve animation, i.e. flexible slip, and a method of birth.

This method will be called in four places View of:

  • draw () because usually call this method, triggering computeScroll () method
  • updateDisplayListIfDirty()
  • buildDrawingCacheImpl () method call this method has been abandoned
  • createSnapshot()

Before introducing elastic slide, first look at the correlation method Scroller

Two, Scroller

In achieving the elastic sliding, only two methods:

  • start scroll
  • computeScrollOffset

Elastic Slide implementation

The following code, the function calls the function directly, is the View. Call smoothScroll () can be achieved resilient slide

   Scroller mScroller = new Scroller(mContext);

   //自定义的函数
   private void smoothScroll(int destX, int destY) {
        int scrollX = getScrollX();
        int deltaX = destX - scrollX;
        mScroller.startScroll(scrollX, 0, deltaX, 0, 500);
        invalidate();
    }


    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }

Let's analyze the source code of these two functions:

   public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;
        mDurationReciprocal = 1.0f / (float) mDuration;
    }

The original startScroll () method is only relevant parameters are initialized, wherein the time startX, startY representative of the start sliding, dx, dy required on behalf of the sliding distance, duration representative of the desired sliding.

This code does not set the view mobile code, how to achieve that is resilient sliding it?

Mystery is in startScroll () immediately followed by a call to invalidate (), eventually calls computeScroll () This custom function, in computeScroll () function, call scrollTo (), then call invalidate (). Constantly calling scrollTo () to view the move to achieve sliding animation.

In computeScroll computeScrollOffset call () () function to determine whether or not to move, and to move to the next position

The following look at the source code computeScrollOffset () function, the code is very simple, comments, write some notes

/**
     * Call this when you want to know the new location.  If it returns true,
     * the animation is not yet finished.
     * 如果返回True,表示动画未完成。返回false,表示动画完成
     */ 
    public boolean computeScrollOffset() {
    	//判断动画是否完成
        if (mFinished) {
            return false;
        }
		//距离动画开始的时间,用这个时间差,配合插值器,计算出下一个动画的位置
        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    
        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                //滑动模式,手指还在屏幕上,配合插值器,计算出下一个动画的位置
                final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
            case FLING_MODE:
                //抛模式,手指滑动离开屏幕,离开屏幕的那一点,手指具有速度
                final float t = (float) timePassed / mDuration;
                final int index = (int) (NB_SAMPLES * t);
                float distanceCoef = 1.f;
                float velocityCoef = 0.f;
                if (index < NB_SAMPLES) {
                    final float t_inf = (float) index / NB_SAMPLES;
                    final float t_sup = (float) (index + 1) / NB_SAMPLES;
                    final float d_inf = SPLINE_POSITION[index];
                    final float d_sup = SPLINE_POSITION[index + 1];
                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;
                }
				//计算出当前的速度
                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
                
                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
                // Pin to mMinX <= mCurrX <= mMaxX
                mCurrX = Math.min(mCurrX, mMaxX);
                mCurrX = Math.max(mCurrX, mMinX);
                
                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
                // Pin to mMinY <= mCurrY <= mMaxY
                mCurrY = Math.min(mCurrY, mMaxY);
                mCurrY = Math.max(mCurrY, mMinY);

                if (mCurrX == mFinalX && mCurrY == mFinalY) {
                    mFinished = true;
                }

                break;
            }
        }
        else {
            mCurrX = mFinalX;
            mCurrY = mFinalY;
            mFinished = true;
        }
        return true;
    }

At this point, the elastic slide principle even introduced over

Published 242 original articles · won praise 775 · Views 2.24 million +

Guess you like

Origin blog.csdn.net/xx326664162/article/details/103420170