关闭

Android事件分发的View的焦点捕捉事件

标签: android
63人阅读 评论(0) 收藏 举报
分类:
事件分发的View的焦点捕捉事件:
ScrollView里面嵌套ListView(不需要时隐藏这个布局), 可以解决滑动问题. 就是滑动到ListView的时候, ScrollView也跟着滑动,这样子联动的效果比较好.
如果是ScrollView里面是一个Fragment,然后Fragment里面是一个ListView, 这样子就无法做到ScrollView和ListView联动的效果了,因为基于事件分发原理,一个焦点只能由一个View捕获,如果不禁止父容器的捕获事件的能力,那么这个嵌套在Fragment的ListView将无法捕获屏幕按下去的这个事件,所以这个ListView在你没有做特殊处理之前是不能滑动的. 你要禁止了父容器捕获事件这个api,然后+ListView才可以滑动,不过有缺点就是ListView和ScrollView不能一起联动.
具体实现的Api如下,要在设置onTouchListener监听的时候, 根据情况对ACTION_UP或者ACTION_DOWN进行单独设置.
listview.setOnTouchListener(new View.OnTouchListener()){
@Override
public boolean onTouch(View v, MotionEvent event){
if(event.getAction == MotionEvent.ACTION_UP)){
v.getParent().requestDisallowInterceptTouchEvent(false);
}else{
v.getParent().requestDisallowInterceptTouchEvent(true); // 屏蔽父容器的拦截事件
}
return false;
}
}

简介:
一个Activity或View的onTouchEvent()回调函数会接收到touch事件(就是这个setOnTouchListener).
调用的时候这两个方法也只是先后顺序的问题.先调用setOnTouchListener(),这个方法里面要你重写onTouch(), 而且调用了onTouch()方法会先于onTouchEvent(). 并且一旦设置了onTouchListener并且最后onTouch()方法返回了true,那么onTouchEvent()就不再被执行,(先执行setOnTouchListener里的onTouch()方法, 再执行onTouchEvent() ) 如果setOnTouchListener的onTouch()方法返回的是false,onTouchEvent()就会继续被调用.

onClickListener和onTouchEvent有些关系, onTouchEvent默认实现是会调用onClickListener里面的onClick()方法,如果重写了onTouchEvent,因为onClickListener接收不到ACTION_DOWN和ACTION_UP,那么再设置onClickListener也就不会再生效了,这时候单击或者长按处理只能在onTouchEvent中自己处理了.


关于事件传递的机制,这里给出一些结论,根据这些结论可以更好地理解整个传递机制,如下所示:
(1)同一个事件序列是指从手指接触屏幕的那一刻起, 到手指离开屏幕的那一刻结束,在这个过程所产生的一系列事件,这个事件序列以down开始,中间含有数量不定的move事件,最终以up事件结束.

(2)正常情况下,一个事件序列只能被一个View拦截且消耗.这一条原因可以参考(3), 因为一旦一个元素拦截了某此事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理, 但是通过特殊手段可以做到, 比如一个View本该将自己处理的事件通过onTouchEvent强行传递给其他View做到.

(3)某个View一旦决定拦截,那么这一事件序列只能由它来处理(如果事件序列能够传递给它的话), 并且它的onInterceptTouchEvent不会再被调用. 这条也很好理解, 就是说当一个View决定拦截一个事件后, 那么系统会把同一个事件序列内的其他方法都直接交给它处理, 因此就不用再调用这个View的onInterceptTouchEvent()来询问它是否要被拦截了.

(4)某个View一旦开始处理事件, 如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false), 那么同一个事件序列中的其他事件都不会交给它处理,并且事件会重新交给到它的父元素去处理, 即父元素的onTouchEvent()会被调用. 意思就是事件一旦交给一个View处理,那么后续的一系列move,up事件都会在这个View中被处理,

(5)如果View不消耗ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理.

(6)ViewGroup默认不拦截任何事件,Android源码的ViewGroup的onInteceptTouchEvent方法默认返回false.

(7)View没有onInterceptTouchEvent方法, 一旦有点击事件传递给它, 那么它的onTouchEvent方法就会被调用.

(8)( Button之所以比较特殊是因为它的clickable为true, 所以Button的onTouchEvent()会返回true, 默认设置为消耗事件. )View的onTouchEvent默认都会消耗事件(返回true), 除非它是不可点击的( clickable和longClickable同时为false ). View的longClickable的属性默认为false, clickable属性要分情况, 比如Button和clickable属性默认为true, 而TextView的clickable属性默认为false.

(9) View的enable属性不影响onTouchEvent的默认返回值. 哪怕一个View是disable状态的, 只要它的clickable或者longClickable有一个为true, 那么它的onTouchEvent就返回true.

onClick()是会对ACTION_DOWN和ACTION_UP两个动作同时发生才作响应.
(10) onClick()会发生的前提是当前View是可点击(enable = true)的, 并且它收到了down和up的事件.

(11) 事件的传递过程是由外向内的, 即事件总是先传递给父元素, 然后再由父元素分发给子View, 通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程, 但是ACTION_DOWN事件除外.



一个完整的手势(事件序列)是
一个完整的事件序列以Down开始, 中间包含若干个Move, 然后以Up结束.
setOnClickListener的优先级是最低的,
官方提供的GestureDetector(手势检测辅助类)给我们提供了可能。
class SimpleGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent e) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; // 猛扔 }}
通过这个类,我们可以很方便的处理除了单击和长按之外,还有滑动,双击等各种手势,并对其分别进行处理,如果这些还是不能满足你的好奇心,那还有一个官方提供的ScaleGestureDetector,从名字就可以判断出来这是一个检测缩放手势的辅助类
private void init() { scaleGesture = new ScaleGestureDetector(getContext(), new ScaleListener()); moveGesture = new MoveGestureDetector(getContext(), new MovingListener()); rotateGesture = new RotateGestureDetector(getContext(), new RotateListener()); } @Override public boolean onTouchEvent(MotionEvent event) { scaleGesture.onTouchEvent(event); moveGesture.onTouchEvent(event); rotateGesture.onTouchEvent(event); return true; } private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { setScaleX(detector.getScaleFactor() * getScaleX()); setScaleY(detector.getScaleFactor() * getScaleY()); return true; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { } }


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:460次
    • 积分:91
    • 等级:
    • 排名:千里之外
    • 原创:9篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    文章存档