基本手势事件
一、事件分发
顺序:Activity->ViewGroup->View
基本的手势事件主要有如下三个方法:
1、dispatchTouchEvent
/**
* 事件的分发
* 分发事件的方法。当接收到事件时,通过调用此方法来决定是否分发。
* @param ev
* @return
* true: 事件不再进行分发且已经在自身事件的分发中被消费
* false: 也不对事件进行分发。
* 也就是说该方法不论是返回true还是返回false都不会对事件进行分发,
* 只有当返回系统默认super.dispatchTouchEvent(ev)时,才会将事件分发给本层 的拦截事件onInterceptTouchEvent(MotionEvent ev)去处理,
* 如果没有onInterceptTouchEvent(MotionEvent ev)方法,则直接分发给子View中的onInterceptTouchEvent(MotionEvent ev)方法处理
*
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
Log.d("data","[LinearLayout]--dispatchTouchEvent:"+ev.getAction()+" "+super.dispatchTouchEvent(ev));
}
return super.dispatchTouchEvent(ev);
}
/*log日志
*EventActivity: dispatchTouchEvent=====ACTION_DOWN
*EventActivity: dispatchTouchEvent=====ACTION_UP
*/
注:View和ViewGroup在dispatchTouchEvent上的区别:
ViewGroup在dispatchTouchEvent()中会进行事件的分发。
View在dispatchTouchEvent()中会对该事件进行处理。
2、onInterceptTouchEvent
/**
* 事件的拦截
* 该方法只有在ViewGroup中才会有。通过调用该方法来决定是否对事件进行拦截。
* 在dispatchTouchEvent的内部调用,用于判断是否拦截某个事件
* @return
* true:进行拦截,将事件进行分发onTouchEvent方法处理
* false:不对事件进行拦截,传递给下一级处理
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(ev.getAction() ==MotionEvent.ACTION_DOWN){
Log.d("data","[LinearLayout]--onInterceptTouchEvent:"+ev.getAction()+" "+super.onInterceptTouchEvent(ev));
}
return super.onInterceptTouchEvent(ev);
}
3、onTouchEvent
/**
* 事件的处理
* 处理事件。当对事件进行了拦截时,将会调用onTouchEvent方法对事件进行处理。
* 在dispatchTouchEvent中调用,用于处理点击事件
* @param ev
* @return
* true: 表示该View能处理该事件,事件将终止向上传递(传递给其父View)
* false: 不能处理,则把事件传递给其父View的onTouchEvent方法来处理
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(ev.getAction() ==MotionEvent.ACTION_DOWN){
Log.d("data","[LinearLayout]--onTouchEvent:"+ev.getAction()+" "+super.onTouchEvent(ev));
}
return super.onTouchEvent(ev);
}
//注意:onTouchEvent事件消费函数一旦返回false 后面的鼠标UP 和 MOVE 就不会在这里执行了,但是下一次down事件能获取到
二、滑动冲突
场景:
1、内层和外层滑动方向不一致:一个垂直,一个水平。比如轮播图ViewPager和ScrollView;
2、内存和外层滑动方向一致:均垂直or水平。比如scrollView和RecyclerView;
3、前两者层层嵌套。比如ScrollView和RecyclerView(recyclerView中又嵌套recyclerView)
处理原则:
1、对于内外层滑动方向不同,只需要根据滑动方向来给相应控件拦截
2、对于内外层滑动方向相同,需要根据业务来进行事件拦截,规定何时让外部View拦截事件何时由内部View拦截事件。
3、前两者嵌套的情况,根据前两种原则层层处理即可。
解决办法:
内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。
外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。
具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。
外部拦截要点:
父容器的onInterceptTouchEvent方法中处理
ACTION_DOWN不拦截,一旦拦截会导致后续事件都直接交给父容器处理。
ACTION_MOVE中根据情况进行拦截,拦截:return true,不拦截:return false(外部拦截核心)
ACTION_UP不拦截,如果父控件拦截UP,会导致子元素接收不到UP进一步会让onClick方法无法触发。此外UP拦截也没什么用。