一。弹性滑动
View的滑动是比较生硬的滑动过去,在瞬间完成,用户体验太差,所以我们要实现弹性滑动。
思想: 将一次大的滑动分成若干次小的滑动,并在一个时间段完成,
实现方式: Scroller ,Handler & postDelayed ,thread & sleep
1.使用Scoller
使用方式已经在上一篇博客中提供代码。View的体系(一)中进行查看:
Scoller的工作原理:
构建一个scoller对象调用startScoll时,Scoller内部什么也没做,只是保存我们传递的参数,代码如下:
通过代码我们可以看出,startX startY表示的滑动的起点,dx,dy表示滑动的距离,
Duration表示滑动的时间。这里的滑动表示的是内容非view的本身,
Scroller通过startScoll方法的invalidate方法进行view的重新绘制,
在view的draw方法中会去调用computeScroll方法,computeScoll向scroller获取当前的ScrollX和ScrollY;
总结:
Scroller本身并不能实现view的滑动,需要配合view的computeScoll方法完成弹性滑动效果。通过不断的让view重新绘制,每次滑动都会有一个时间间隔,通过这个时间间隔得出view的滑动位置,再通过ScrollTo方法完成滑动,就这样每一次绘制都会导致ciew进行小幅度的滑动,多次组合成弹性滑动;
2.通过动画
动画本身就是一种渐进的过程,因此他本身就具备弹性效果,
例如:让view的内容在100ms向左移动100像素
- 使用动画模仿Scoller来实现view的滑动
通过上诉代码发现,思想和Scoller比较类似,通过一个百分比分配scollTo方法完成view的滑动。
3.使用延迟策略
延迟策略的核心:
通过发送一系列延时消息从而达到一种渐进式的效果,使用handler。View的postDelayed方法;
,也可以使用线程的方法;
- 举例(使用handler)
二。View的事件分发机制
1.什么是事件分发过程
当一个点击事件产生以后,系统需要把这个事件传递给一个具体的view,这个传递过程就是分发过程。分发过程有三个重要方法来共同完成;
2.dispachTouchEvent
用来进行事件分发,如果事件能够传递给view,那么此方法一定会被调用,返回结果和当前view的onTouchEvent和下级view的dispatchTouchEvent方法影响,表示是否消耗当前事件
3.onInterceptTonchEvent
用于判断是否拦截某个事件,如果当前view拦截某个事件,那么在同一个事件序列中,此方法不会被调用,表示是否拦截当前事件
4.onTouchEvent
在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,
如果不消耗则在同一个事件序列中,当前view无法再次接收到事件
- 三者的关系
通过上诉代码可以直观的发现三者关系:
对于一个根viewGroup来说,点击事件产生,dispatchTouchEvent方法就会被调用;如果viewGroup的onInterceptTouchEvent方法返回true,表示拦截当前事件,事件交给这个viewGroup进行处理,如果返回false,表示不拦截当前事件,事件会传递给它的子元素,子元素的dispatchTouchEvent方法就会被调用,直到事件被最终处理;
2)优先级问题
当一个view需要处理事件时,设置了onTouchListener,onTouch方法就会被回调,事件的处理需要看onTouch返回值,返回true,onTouchEvent方法不会被调用,返回false,onTouchEvent方法会被调用;
可见,View设置的onTouchListener优先级比onTOuchEvent高;在onTOuchEvent方法中,如果当前设置有onClickListener,那么onClick会被调用,所以onClickListener优先级最低
3)事件传递的机制
一个事件产生后,传递过程:activity----window ----- view 即事件总是最先传递给acitivty ----àwindow --------àview,当view接收到事件后,就会按照事件分发机制去分发事件;如果一个view的onTOuchEvent返回false,他的父容器onTOuchEvent方法就会被调用,依次类推,最终事件将会传递给activity进行处理;
- 关于事件传递机制,总结:
- 同一事件的序列指:用户手指触摸到屏幕,到离开屏幕那一刻结束,(down -àmove ---àup)
- 一个事件序列只能被一个view拦截消耗,
- 某个view一旦决定拦截,那么一个事件序列只能由他来处理,并且onInterceptTouchEvent方法不会再被调用,
- 某一个view一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTOuchEvent返回false),那么同一事件序列其他事件都不会再交给它处理。并且事件将重新交给父元素去处理;
- 如果view不消耗除ACRTION_DOWN以外的其他事件,那么这个点击事件就会消失,此时父元素的onTOuchEvent不会被调用,并当前view可以持续收到后续的事件,最终消失的事件会传递给activity进行处理
- ViewGroup默认不拦截任何事件,相当于viewGroup的onInterCeptTouchEvent方法返回false
- View 没有onInterceptTOuchEvent方法,一旦点击事件传递给它,他的onTouchEvent方法就会被调用;