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不动。
网友评论