了解滑动实现原理后,可以总结出实现滑动效果的基本思想:当View被触摸时,记录当前触摸点的坐标;当触摸点移动时,记录移动后触摸点的坐标;根据两次获取的坐标计算出触摸点的偏移量,通过偏移量修改View的坐标;不断重复,实现滑动效果。
接下来介绍实现滑动效果的一些方法。
layout方法
在View进行绘制时,会调用onLayout()方法设置显示的位置,因此,可以通过修改View的left,top,right,bottom属性来控制View的坐标。具体在onTouchEvent()方法中实现,示例代码如下:
1 |
|
面的示例代码是通过getX()和getY()方法获取触摸事件的坐标值,下面以getRawX()和getRawY()方法来获取坐标值实现滑动效果:
1 |
|
注意
使用绝对坐标系时,每次执行完ACTION_MOVE逻辑后,一定要重新设置初始坐标,这样才能准确获取连续移动时的偏移量。因为在相对坐标系中,ACTION_DOWN事件的坐标值对于View是不变的,而在绝对坐标系中,这个坐标值对于View是变化的。
offsetLeftAndRight和offsetTopAndBottom方法
这两个方法只需要偏移量就可以完成View的重新绘制,达到layout方法同样的效果,示例代码如下:
1 |
|
LayoutParams
LayoutParams保存了View的布局参数,可以通过改变LayoutParams来动态修改View的位置参数,实现View的滑动效果。具体示例代码如下:
1 |
|
scrollTo与scrollBy方法
View提供了scrollTo与scrollBy方法来改变View的位置,scrollTo(x, y)表示移动到坐标点(x, y),scrollBy(dx, dy)表示移动的增量为dx、dy。
scrollTo与scrollBy方法的本质是移动View,从而使View中content产生相对移动。以下示意图以scrollBy方法为例进行说明:
从示意图可以看出,content移动的方向和ViewGroup移动的方向是相反的,所以,如果以子View的偏移量来移动ViewGroup来达到子View的滑动效果,那么,scrollBy中的偏移量要使用负值。
根据以上分析,使用scrollBy方法实现滑动效果的示例代码如下:
1 |
|
类似的,在绝对坐标系中,可以使用scrollTo方法实现同样的滑动效果。
Scroller
在使用scrollTo与scrollBy方法移动时,View的移动都是瞬时完成的,为了产生平滑移动的效果,需要使用Scroller类。
Scroller的原理也是使用scrollTo与scrollBy方法来移动View,但是它会把移动的偏移量分为多个很小的偏移量,虽然在每个小的偏移量里面,移动是瞬时的,但是整体上会是一个平滑的移动效果。
使用Scroller类实现滑动效果需要以下几个步骤:
- 初始化Scroller
1 | mScroller = new Scroller(context); |
- 重写computeScroll()方法,实现平滑移动
系统绘制View的时候会在draw()方法中调用computeScroll()方法,可以在computeScroll()中使用scrollTo()方法进行小的偏移量的移动,接着调用invalidate()方法触发draw()方法,形成一个循环过程,最终实现平滑移动。示例代码如下:
1 |
|
Scroller类提供了computeScrollOffset()方法来判断是否完成了整个滑动过程,用时提供了getCurX()、getCurY()方法获取当前的滑动坐标。
- 执行startScroll()方法,执行滑动过程
1 |
|
通常使用getScrollX()和getScrollY()方法获取滑动的起始坐标,由于是父视图在滑动,因此,偏移值的正负情况与scrollTo、scrollBy方法相同。同时,需要注意调用invalidate()触发computeScroll()方法进行滑动过程。
位移动画
位移动画(Translate Animation)可以实现View的移动效果,其本质是改变View的translationX和translationY值。因此,可以使用位移动画实现View的滑动效果,具体实现可以参考动画机制相关的文章。
ViewDragHelper
Android的Support库中提供了DrawerLayout和SlidingPaneLayout方便实现侧滑菜单的效果,这两个布局就是通过ViewDragHelper类实现的。通过ViewDragHelper类,基本可以实现各种不同的Scroll、Drag需求。
ViewDragHelper功能比较强大,使用也相对比较复杂,具体使用可以搜索相关资料,这里就不详细介绍了。