Scroller

Scroller 源码

public class Scroller { 
 
  //....
  private int mStartX;  //起始坐标点 , X轴方向 
  private int mStartY;  //起始坐标点 , Y轴方向 
  private int mCurrX;   //当前坐标点 X轴, 即调用startScroll函数后,经过一定时间所达到的值 
  private int mCurrY;   //当前坐标点 Y轴, 即调用startScroll函数后,经过一定时间所达到的值 
   
  private float mDeltaX; //应该继续滑动的距离, X轴方向 
  private float mDeltaY; //应该继续滑动的距离, Y轴方向 
  private boolean mFinished; //是否已经完成本次滑动操作, 如果完成则为 true 
 
  //构造函数 
  public Scroller(Context context) { 
    this(context, null); 
  } 
  public final boolean isFinished() { 
    return mFinished; 
  } 
  //强制结束本次滑屏操作 
  public final void forceFinished(boolean finished) { 
    mFinished = finished; 
  } 
  public final int getCurrX() { 
    return mCurrX; 
  } 
   /* Call this when you want to know the new location. If it returns true, 
   * the animation is not yet finished. loc will be altered to provide the 
   * new location. */  
  //根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中 
  public boolean computeScrollOffset() { 
    if (mFinished) { //已经完成了本次动画控制,直接返回为false 
      return false; 
    } 
    int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); 
    if (timePassed < mDuration) { 
      switch (mMode) { 
      case SCROLL_MODE: 
        float x = (float)timePassed * mDurationReciprocal; 
        ... 
        mCurrX = mStartX + Math.round(x * mDeltaX); 
        mCurrY = mStartY + Math.round(x * mDeltaY); 
        break; 
      ... 
    } 
    else { 
      mCurrX = mFinalX; 
      mCurrY = mFinalY; 
      mFinished = true; 
    } 
    return true; 
  } 
  //开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达坐标为(startX+dx , startY+dy)出 
  public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
    mFinished = false; 
    mDuration = duration; 
    mStartTime = AnimationUtils.currentAnimationTimeMillis(); 
    mStartX = startX;    mStartY = startY; 
    mFinalX = startX + dx; mFinalY = startY + dy; 
    mDeltaX = dx;      mDeltaY = dy; 
    ... 
  } 
  //....


   //计算最终的滚动位置
    public void fling(int startX, int startY, int velocityX, int velocityY,
            int minX, int maxX, int minY, int maxY)
} 

Scroller的原理

Scroller的用法

   基本可概括为“三部曲”: 

1、创建一个Scroller对象,一般在View的构造器中创建:

  public PageLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }

2、重写View的computeScroll()方法,下面的代码基本是不会变化的:

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

3、调用startScroll()方法,startX和startY为开始滚动的坐标点,dx和dy为对应的偏移量 或

filling  一般在touch事件中处理

case MotionEvent.ACTION_UP:
               ...
               // mScroller.startScroll(0, getScrollY(), 0, mDisScreenHeight - dScrollY); 
             mScroller.fling(scrollX, scrollY, -xVelocity, -yVelocity, 0, getWidth() -                 
             chileView.getWidth(), 0, getHeight() - chileView.getHeight());
                    int startX = mScroller.getStartX();  
               ...     
             break;

//简单demo

package com.example.myapplication.touch;

import android.content.Context;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class TestScroller extends ViewGroup {

    private RectF mChildeRectF;
    private VelocityTracker velocityTracker;
    private Scroller mScroller;
    private int mMaxFlintVelocity, mMinFlintVelocity;
    private int mChildMeasuredWidth, mChildMeasuredHeight;
    private View mChildView;
    private float mLastX, mLastY;

    public TestScroller(Context context) {
        this(context, null);
    }

    public TestScroller(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TestScroller(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData(context);
    }

    private void initData(Context context) {
        mChildeRectF = new RectF();
        mScroller = new Scroller(context, null, true);
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        mMaxFlintVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
        mMinFlintVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mChildView = getChildAt(0);
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        mChildMeasuredWidth = mChildView.getMeasuredWidth();
        mChildMeasuredHeight = mChildView.getMeasuredHeight();
        mChildeRectF.set(measuredWidth / 2 - mChildMeasuredWidth / 2, measuredHeight / 2 - mChildMeasuredHeight / 2, measuredWidth / 2 + mChildMeasuredWidth / 2, measuredHeight / 2 + mChildMeasuredHeight / 2);
        mChildView.layout(measuredWidth / 2 - mChildMeasuredWidth / 2, measuredHeight / 2 - mChildMeasuredHeight / 2, measuredWidth / 2 + mChildMeasuredWidth / 2, measuredHeight / 2 + mChildMeasuredHeight / 2);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
        }
        velocityTracker.addMovement(event);
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastX = event.getX();
                mLastY = event.getY();
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                float ev_x = event.getX();
                float ev_y = event.getY();
                int disx = (int) (-ev_x + mLastX);
                int disy = (int) (-ev_y + mLastY);
                scrollBy(disx, disy);
                mLastX = ev_x;
                mLastY = ev_y;
                break;
            case MotionEvent.ACTION_UP:
                //手指抬起,计算当前速率
                float up_x = event.getX();
                float up_y = event.getY();
                velocityTracker.computeCurrentVelocity(1000, mMaxFlintVelocity);
                int xVelocity = (int) velocityTracker.getXVelocity();
                int yVelocity = (int) velocityTracker.getYVelocity();
                int scrollX = getScrollX();
                int scrollY = getScrollY();
                if (Math.abs(xVelocity) > mMinFlintVelocity && Math.abs(yVelocity) > mMinFlintVelocity) {
                    mScroller.fling(scrollX, scrollY, -xVelocity, -yVelocity, 0, getWidth() - mChildView.getWidth(), 0, getHeight() - mChildView.getHeight());
                    int startX = mScroller.getStartX();
                    int startY = mScroller.getStartY();
                    int finalX = mScroller.getFinalX();
                    int finalY = mScroller.getFinalY();
                    mChildeRectF.set(mChildView.getLeft() - finalX, mChildView.getTop() - finalY, mChildView.getRight() - finalX, mChildView.getBottom() - finalY);
                    int dex_x, dex_y;
                    if (up_x > mLastX) {
                        //证明往右滑动
                        dex_x = finalX - startX;
                    } else {
                        dex_x = startX - finalX;
                    }
                    if (up_y > mLastY) {
                        dex_y = finalY - startY;
                    } else {
                        dex_y = startY - finalY;
                    }
//                    awakenScrollBars(mScroller.getDuration());
                    invalidate();
                } else {
                    mChildeRectF.set(mChildView.getLeft() - scrollX, mChildView.getTop() - scrollY, mChildView.getRight() - scrollX, mChildView.getBottom() - scrollY);
                }

                if (velocityTracker != null) {
                    velocityTracker.clear();
                }
                break;

        }
        return true;
    }


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

猜你喜欢

转载自blog.csdn.net/TyearLin/article/details/119997125