1. 坐标系
一图解析坐标系
-
TouchEvent.getX():点击事件到控件左边的距离 -
TouchEvent.getRawX():点击事件到屏幕左边的距离 -
getTop():View自身定边到其父布局的距离。getBottom等与之对应
2. View滑动
- ScrollTo/ScrollBy,只能滑动内容,如果是View个Group的话,就是滑动子View。这种方法修改的是
mScrollX和mScrollY,这两个值初始值为0,含义是View边缘到内容边缘的距离。mScrollX>0表示内容向左滑动。 - 动画,适合复杂的没有交互的滑动。滑动只是改变了
translationX和translationY并没有实际改变View的位置,监听器会停留在之前的地方。 - 修改布局参数,适合有交互的滑动
(Layout,OffsetLeftAndRight...等滑动方式,均属于属于修改布局参数)
3. 弹性滑动
修改参数和使用ScrollTo的滑动都是一蹴而就的,缺少人生的体验。使用动画又会导致灵魂和肉体分离。想要天人合一的滑动就需要使用弹性滑动。
弹性滑动有点类似于微分的思想,将滑动细化,然后滑动一点显示一点,直到滑动完成。
3.1 Scroller实现
源码执行步骤是:
- 记录当前时间
beginTime -
invalidate()重绘调用draw(),draw()调用computeScroll() - 记录当前时间
nowTime,得到(nowTime - beginTime)/duration这个比值就是这次要滑动的路程和总路程的比值,这一步很巧妙。如果比值小于1,根据比值得到要滑动的距离,修改布局参数,调用invalidate()重绘重复3。否则结束滑动。
3.2 使用动画
准确的是使用动画特性。借助valueAnimator这个类,例如ValueAnimator.ofInt(0,1).setDuration(2000),它会在2秒内不停的给你返回一个小数,范围[0,1],再看看Scroller,是不是很像,也是微分法。每次返回一个递增的小数,我们就使用ScrollTo来修改空间的位置,最后达到平滑滑动。
3.3 使用延时策略
在handleMessage()中使用Handler.SendMessageDelayed()。和Scroller的策略很像。收到消息后,移动一小段,然后间隔很短的时间发送一条消息,收到消息再移动一小段,如此往复,直到时间到了。
4. View事件分发机制
-
public boolean dispatchTouchEvent(MotionEvent ev):是否将事件传递给下一级,返回的结果受下一级的dispatchTouchEvent()和当前的onTouchEvent() -
public boolean onInterceptTouchEvent(MotionEvent ev):在上面函数内部调用,当前View是否拦截事件,返回true表示拦截,返回false表示不拦截。 -
public boolean onTouchEvent(MotionEvent ev):用来处理事件,返回true表示消耗,返回false表示不消耗。
用《进阶之光》上的例子就是:
敌人来挑战武当山,武当山上现在有掌门张三丰,武当七侠宋远桥,武当弟子宋青书。张三丰肯定不会直接出动(onInterceptTouchEvent == false),而是让宋远桥去(child.dispathcTouchEvent(ev)),宋远桥(ViewGroup)也威名远扬,也不会轻易应战(onInterceptTouchEvent == false),派遣宋青书(child.dispathchTouchEvent(ev),宋青书(底层的View) 没有徒弟了(没有child了),只好自己去迎战... 这就是事件的从上向下传递。
结果挑战的是成昆,宋青书处理不掉他(onTouchEvent = false),于是叫宋远桥来,结果宋远桥也不是对手(onTouchEvent = false),于是张三丰只好亲自出马(调用 onTouchEvent())。
5. 滑动冲突
- 左右嵌套上下滑动冲突,根据滑动的左右分量和上下分量的大小来解决。
- 左右嵌套左右滑动冲突,根据具体的业务来解决。在实际开发中可以判断内存View是否滑动到了尽头,如果滑动到了尽头再滑动外层View,否则外层View不动。







网友评论