Android中View的滑动(一)

坐标系

安卓内部的坐标系分为两套坐标系,为安卓坐标系和视图坐标系。(似乎还有个全局坐标)

如图所示

视图坐标系(相对坐标)

视图坐标系的坐标是指以其parent视图的左上角为原点,x轴向右、y轴向下的一套坐标系。我们可以通过如下的一些方法获得该坐标系下的坐标点。

  • View中的方法:getTop、getBottom、getLeft、getRight。这些方法获得的都分别是这个view的左上角那一个点以及右下角那一个点的坐标的横纵坐标值;
  • MotionEvent提供的方法:getX、getY

安卓坐标系(绝对坐标)

该坐标系是指以屏幕上的左上角(实则就是整个window的左上角那个点)为原点,x轴向右、y轴向下的一套坐标系。有这样的方法可以获得该坐标:

  • MotionEvent提供的方法:getRawX、getRawY
  • 1
    2
    3
    4
    int[] location = new int[2] ;
    view.getLocationInWindow(location); //获取在当前窗口内的绝对坐标
    view.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标
    location [0]--->x坐标,location [1]--->y坐标

    要注意的是,这段代码需要在UI全部加载完毕之后调用才有效果,直接在onCreate中调用的话,所有返回的参数都会是0。

使用Scroller实现滑动

scroller实现滑动的原理还是通过view的ScrollTo以及ScrollerBy两个方法来实现。(实际上ScrollBy在原理上,也是通过包装ScrollTo之后得到的一个方法)

要注意的是scrollTo与scrollBy两个方法改变的是view内部的内容的“补偿值”,即getScrollX、getScrollY得到的两个值。这个滑动补偿值是等于view的左边界减去内容的左边界的值。

如图所示

重写computeScroll

当view调用draw方法的时候会调用这个方法,不过在view里面computeScroll方法是个空实现方法,我们重写这个方法就可以使view在每一次重绘的时候调用并且scroll了。

1
2
3
4
5
6
7
@Override
public void computeScroll(){
if(scroller.computeScrollOffset()){
this.scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}

computeScrollOffset这个方法将会计算此时的所谓“滑动补偿值”,当其返回true的时候表明滑动过程还没有结束,并且此时可以调用getCurrX以及getCurrY方法来获得其当前补偿值。(这里的postInvalidate方法是向主线程发起重绘的方法,实际测试中用普通的invalidate也不会报错……)

包装Scroll的方法实现

1
2
3
4
5
6
public void smoothScrollTo(int desX, int desY){
int curX = getScrollX();
int curY = getScrollY();
scroller.startScroll(curX, curY, desX - curX, desY - curX, 1000);
invalidate();
}

当我们设置好了Scroller之后,就通过invalidate来发起重绘过程就可以了。

实现效果

如图所示

总结

1.Scroller类里面完全没有view的对象,两者的解耦度是非常高的,这是一种很值得学习的设计方式;
2.computeScroll方法中的scrollTo的调用者可以换成其他的对象,比如说强制转化之后的getParent,这样就可以使得整个view都在移动,而不是只是view内部的内容在移动。(同时,这样做的坏处是显而易见的……)

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2018 Alex's Blog All Rights Reserved.

Yifeng Tang hält Urheberrechtsansprüche.