Android 进阶之事件交互 二 滑动事件
滑动原理
实现View的滑动如下图所示:
图上通过滑动从将圆形从黄色地方移到灰色地方,从图上很明显看出,要实现这种移动只需要计算出滑动的偏移量,然后通过原始坐标就可以计算出最终坐标的位置,因此我们需要获得如下信息:
- 第一次相对于View的坐标
- 再次按下的时候相对于View的坐标
- 根据上面两个坐标即可计算出两次的偏移量,有了偏移量就可以移动View了,不断重复上述步骤就实现了滑动过程。
大体的结构如下,接下来我们的重点将放在如何实现processTouchEvent这个方法来实现滑动。
private float originX = -1; |
滑动的实现
使用layout方法
在绘制View的时候,会调用layout方法并传入left,top,right,bottom来移动View。
private void processTouchEvent(Context context,float offsetX,float offsetY) { |
使用LayoutParams
这种适用于要移动的View位于一个Layout中的情形,因为移动一个View通常是通过修改它在Parent View 中的margin来实现的。所以可以通过这种方式来实现:
private void processTouchEvent(float offsetX,float offsetY) { |
使用ScrollTo和ScrollBy
在使用这两个方法移动视图的时候,移动的不是View或者ViewGroup本身,而是View 或者ViewGroup的包含的内容,比如TextView 使用这两种方式移动的时候移动的将是TextView的文本,
而一个Layout移动的时候移动的将是里面的子View,那么我们怎样移动一个View本身,而不是仅仅其内容呢?很简单换位思考下,站在要移动View的父类的角度,它不就是父类的内容吗?
有了这个思路就好办了。
private void processTouchEvent(float offsetX,float offsetY) { |
但是这里我们需要时时刻刻让自己记住,这里移动的是父类的位移,而子View的移动偏移实际上是和父View移动位移的相反数。因此要达到我们的移动目标必须将上面的偏移量取相反数。
private void processTouchEvent(float offsetX,float offsetY) { |
使用Scroller
Scroller存在的意义就是为了避免ScrollTo和ScrollBy带来的瞬间移动的效果,它的移动效果会更加平滑。
- 创建Scroller
mScroller = new Scroller(context); - 覆写computeScroll方法
computeScroll 方法是什么时候执行的呢?我们知道在调用invalidate会调用onDraw来重绘当前的页面,在onDraw方法中会调用computeScroll
下面是一个典型的实现,首先调用computeScrollOffset来判断时候完成整个滑动,如果返回true,则表示滑动过程还没结束。我们需要继续滑动@Override
public void computeScroll() {
super.computeScroll();
//If it returns true, the animation is not yet finished.
if(mScroller.computeScrollOffset()) {
((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
invalidate();
}
} - 调用startScroll启动滑动过程:
case MotionEvent.ACTION_UP:
mScroller.startScroll(xpos,ypos,((View)getParent()).getScrollX(),((View)getParent()).getScrollY());
invalidate();
由于这种方法十分重要所以在这里将对Scroller常用的方法做个总结:
mScroller.getCurrX() //获取mScroller当前水平滚动的位置 |