Android Scroll分析

Android Scroll分析

常用的一些方法

View 提供的获取坐标方法

getTop(): 获取到的是View自身的顶边到其父布局顶边的距离

getLeft(): 获取到的是View自身的左边到其父布局左边的距离

getRight(): 获取到的是View自身的右边到其父布局左边的距离

getBottom(): 获取到的是View自身的底边到其父布局顶边的距离

MotionEvent提供的方法

getX(): 获取点击事件距离控件左边的距离,即视图坐标
getY(): 获取点击事件距离控件顶边的距离,即视图坐标
getRawX(): 获取点击事件距离整个屏幕左边的距离,即绝对坐标
getRawY(): 获取点击事件距离整个屏幕顶边的距离,即绝对坐标

在View进行绘制时,会调用onLayout()方法来设置显示的位置。可以通过修改View的left、top、right、bottom四个属性来控制View的坐标。
layout(left+offsetX,top+offsetY,right+offsetX,bottom+offsetY) = offsetLeftAndRight(offsetX), offsetTopAndBottom(offsetY)。

LayoutParams

通过getLayoutParams()获取LayoutParams时,需要根据view所在父布局的类型来设置不同的类型。如果父布局是LinearLayout,就可以使用LinearLayout.LayoutParams。如果父布局是RelativeLayout,就可以使用RelativeLayout.LayoutParams。前提是有一个父布局,不然系统无法获取LayoutParams。

使用ViewGroup.MarginLayoutParams更加的方便,不需要考虑父布局的类型,当然他们的本质都是一样的。

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

scrollTo和scrollBy

scrollTo(x,y)表示移动到一个具体的坐标点(x,y),而scrollBy(dx,dy)表示移动的增量为dx,dy。

scrollTo、scrollBy方法移动的是View的content,即让View的内容移动。如果在ViewGroup中使用scrollTo、scrollBy方法,那么移动的将是所有子View。

scrollBy

当我们调用scrollBy(20,10)移动的时候,效果如下:

移动后

这是为什么呢?

虽然设置scrollBy(20,10),偏移量均为X轴,Y轴正方向的正数,但是在屏幕的可视区域内,Button却向X轴,Y轴负方向上移动了,这就是因为参考下选择的不同,而产生的不同效果。

Scroller

scrollTo还是scrollBy,子View的移动都是瞬时完成的,Scroller就是为了实现平滑移动的效果,而不是瞬间完成的移动。使用Scroller需要如下三个步骤:

  1. 初始化Scroller
mScroller = new Scroller(context);
  1. 重写computeScroll()方法,实现模拟滑动

    @Override
    public void computeScroll(){

    super.computeScroll();
    if(mScroller.computeScrollOffset()){
        ((View)getParent()).scrollTo(mScroller.getSurrY(),mScroller.getCurrY());
    
        invalidate();
    }
    

    }

  2. startScroll开启模拟过程

    public void startScroll(int startX,int startY,int dx,int dy,int duration)

    public void startScroll(int startX,int startY,int dx,int dy)

ViewDragHelper

  1. 初始化ViewDragHelper

    mViewDragHelper = ViewDragHelper.create(this,callback);

  2. 拦截事件

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){

    return mViewDragHelper.shouldInterceptTouchEvent(ev);
    

    }

    @Override
    public boolean onTouchEvent(MotionEvent event){

    mViewDragHelper.processTouchEvent(event);
    return true;
    

    }

  3. 处理computeScroll()

    @Override
    public void computeScroll(){

    if(mViewDragHelper.continueSettling(true)){
        ViewCompat.postInvalidateOnAnimation(this);
    }
    

    }

  4. 处理回调Callback

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback(){

    @Override
    public boolean tryCaptureView(View child,int pointerId){
    
        //如果当前触摸的child是mMainView时开始检测
        return mMainView == child;
    }
    

    };

clampViewPositionHorizontal(View child,int left,int dx)和clampViewPositionVertical(View child,int top,int dy)。