学习使用安卓scroller

Android Scroller 解读编写Demo

Scroller是一个专门用于处理滚动效果的工具类,大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。而如果能够把Scroller的用法熟练掌握的话,对于之后使用ViewPager更容易上手。

直接上源码,代码已经做了详细解读:

public class ScrollerLayout extends ViewGroup {

/**
 * 用于完成滚动操作的实例
 */
private Scroller mScroller;
/**
 * 判定为拖动的最小移动像素数
 */
private int mTouchSlop;
/**
 * 手机按下时的屏幕坐标
 */
private float mXDown;
/**
 * 手机当时所处的屏幕坐标
 */
private float mXMove;
/**
 * 上次触发ACTION_MOVE事件时的屏幕坐标
 */
private float mXLastMove;
/**
 * 界面可滚动的左边界
 */
private int leftBorder;
/**
 * 界面可滚动的右边界
 */
private int rightBorder;


public ScrollerLayout(Context context, AttributeSet attr) {
    super(context,attr);
    // 第一步,创建Scroller的实例
    mScroller=new Scroller(context);
    ViewConfiguration configuration=ViewConfiguration.get(context);
    //能够识别的最小滑动举例 ViewConfiguration.getScaledTouchSlop();
    //获取TouchSlop值
        mTouchSlop= configuration.getScaledTouchSlop();
}

//定义View的位置在ViewGroup中的位置
//1)参数changed表示view有新的尺寸或位置;
//2)参数l表示相对于父view的Left位置;
//3)参数t表示相对于父view的Top位置;
//4)参数r表示相对于父view的Right位置;
//5)参数b表示相对于父view的Bottom位置。.
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
      if(changed){
          int childCount=getChildCount();
          for (int i=0;i<childCount;i++){
              View childView=getChildAt(i);
              // 为ScrollerLayout中的每一个子控件在水平方向上进行布局
              //layout(a,b,c,d)中的四个参数是相对于父布局定义的
              //a和 b 是控件左边缘和上边缘相对于父类控件左边缘和上边缘的距离。

             // c 和 d是空间右边缘和下边缘相对于父类控件左边缘和上边缘的距离。
              childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1) * childView.getMeasuredWidth(), childView.getMeasuredHeight());
          }
          // 初始化左右边界值
          leftBorder = getChildAt(0).getLeft();
          rightBorder = getChildAt(getChildCount() - 1).getRight();
      }

}

//View本身大小多少,由onMeasure()来决定
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //返回包含View的个数
    int childCount=getChildCount();
    for(int i=0;i<childCount;i++){
        //获取布局中的view
        View childView=getChildAt(i);
        //规定了每个子view的尺寸,与当前的父View保持一致
        measureChild(childView,widthMeasureSpec,widthMeasureSpec);
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    switch (ev.getAction()){
        //手指按下
        case MotionEvent.ACTION_DOWN:
            //获取绝对坐标,相对于屏幕的X坐标
            mXDown = ev.getRawX();
            mXLastMove = mXDown;
            break;
        //手指滑动
        case MotionEvent.ACTION_MOVE:
            mXMove = ev.getRawX();
            float diff = Math.abs(mXMove - mXDown);
            mXLastMove = mXMove;
            // 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
            if (diff > mTouchSlop) {
                return true;
            }
            break;

    }
    return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()){
        case MotionEvent.ACTION_MOVE:
            mXMove=event.getRawX();
            int scrolledX=(int)(mXLastMove-mXMove);
            //getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量
            if(getScrollX()+scrolledX<leftBorder){
                scrollTo(leftBorder, 0);
                return true;
            }else if(getScrollX() + getWidth()+scrolledX >rightBorder){
                scrollTo(rightBorder - getWidth(), 0);
                return true;
            }
            scrollBy(scrolledX, 0);
            mXLastMove = mXMove;
            //手指离开屏幕
        case MotionEvent.ACTION_UP:
            // 当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
            int targetIndex = (getScrollX() + getWidth() / 2) / getWidth();
            int dx = targetIndex * getWidth() - getScrollX();
            // 第二步,调用startScroll()方法来初始化滚动数据并刷新界面
           //invalidate()函数的主要作用是请求View树进行重绘
           // startScroll执行过程中即在duration时间内,
            // computeScrollOffset 方法会一直返回false,但当动画执行完成后会返回返加true.
            mScroller.startScroll(getScrollX(), 0, dx, 0);
            invalidate();
            break;
    }
    return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
    // 第三步,重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        //invalidate()函数的主要作用是请求View树进行重绘
        invalidate();
    }
}

activity_main.xml

这里写图片描述

参考:http://blog.csdn.net/guolin_blog/article/details/48719871
http://www.jianshu.com/p/0c863bbde8eb
http://blog.csdn.net/pi9nc/article/details/18764863

猜你喜欢

转载自blog.csdn.net/baidu_30891377/article/details/76541236