Android关于触摸事件跟点击事件两个方法的关系
2017-10-07 11:55
686 查看
Android事件分发机制完全解析,带你从源码的角度彻底理解(上) - 郭霖的专栏 - CSDN博客 http://blog.csdn.net/guolin_blog/article/details/9097463/#reply
在这篇博客里面,郭霖先生说到Button是默认可以点击的,但ImagView是不可以默认点击的以及onTouch方法触发点击事件,本来不打算写的,直到看到网上有一些人写的这些都乱七八糟,所以觉得还是需要自己看一遍记下来
这里可以试试
可以看出Button是默认可以点击的,但ImagView是不可以默认点击的
这里小弟刚开始查看了一下源码,发现了Button跟ImageView的onTouchEvent都是在他们共同的父类实现的,但由于源码级别不够,所以做了下面这个实验
1.MyButton
2.MyImageView
最后在activity_main里面使用
同时在Activity里面打印分发以及处理事件的方法
当你点击Button时候的情景:
I/xx: MainActivity的dispatchTouchEvent0
I/xx: MyButton的onTouchEvent–0
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MyButton的onTouchEvent–2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MyButton的onTouchEvent–2
I/xx: MainActivity的dispatchTouchEvent1
I/xx: MyButton的onTouchEvent–1
你会发现Button的onTouchEvent把DOWN,MOVE以及UP事件都消费了(事件作用在Button身上的时候)
当你点击ImageView时候的情景:
I/xx: MainActivity的dispatchTouchEvent0
I/xx: MyImageView的onTouchEvent–0
I/xx: MainActivity的onTouchEvent0
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent1
I/xx: MainActivity的onTouchEvent1
这里可以看出,Button是默认可以点击的,ImageView是默认不可以被点击的,上源码
你会发现一个clickable为true就可以走到click事件啦,同时在这里也可以看出touch事件的UP事件才会触发click事件
1.Button默认消费全部事件(DOWN,MOVE以及UP事件),而ImageView不会
这里是View里面的源码,可以看出只要你注册了一个OnClickListener接口,那么你都是Clickable(可点击状态),或者你在xml文件中往组件添加 android:onClick=”“属性,那么该组件也是可点击状态啦,这样做都是为了为了让onTouch事件可以触发点击事件
这里阐述了一个问题:
这里也可以看出一个知识点,
1.DOWN事件去确定消费者(可能是拦截,然后自己消费了该事件),然后MOVE以及UP分发过程中遇到消费者之后就不再向下传了,如果消费者不消费MOVE或者UP事件,那么就直接传给Activity去处理
2.分发过程中拦截的是DOWN事件(说明这时候还没有消费者),那么其本身的onTouch方法不消费,那么就上传给他的父亲(他父亲不消费,那么又上传给他爷爷),一层层上去直到找到消费者
3.分发过程中拦截的是MOVE事件或者UP事件,,如果其本身不消费MOVE或者UP事件,那么就直接传给Activity去处理,这里也解释了为什么拦截方法是在分发过程中进行拦截的,并且如果你在DOWN retrun true ,则DOWN,MOVE,UP子View都不会捕获事件(作为消费者,优先处理MOVE跟UP事件了);如果你在MOVE return true , 则子View在MOVE和UP都不会捕获事件。
原因很简单,当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ;
这样设计的目的我觉得是MOVE事件太多了,如果像DOWN事件这样回传,系统负荷太重了
推荐博客:
1.Android事件分发机制完全解析,带你从源码的角度彻底理解(上) - 郭霖的专栏 - CSDN博客 -浅显易懂
2.Android ViewGroup事件分发机制 - Hongyang - CSDN博客 -这个才是真正的源码级分析(最值得一看,虽然我看晕了)
3.Android中事件分发机制 - qq97206858的博客 - CSDN博客
————-我是低调的分割线————————–
如果对你有帮助,可以点击“推荐”哦`(*∩_∩*)′
在这篇博客里面,郭霖先生说到Button是默认可以点击的,但ImagView是不可以默认点击的以及onTouch方法触发点击事件,本来不打算写的,直到看到网上有一些人写的这些都乱七八糟,所以觉得还是需要自己看一遍记下来
这里可以试试
bt_click = (MyButton) findViewById(R.id.bt_click); iv_image = (MyImageView) findViewById(R.id.iv_image); Log.i(TAG,"bt_click的Clickable状态"+bt_click.isClickable());//true Log.i(TAG,"iv_image的Clickable状态"+iv_image.isClickable());//false
可以看出Button是默认可以点击的,但ImagView是不可以默认点击的
这里小弟刚开始查看了一下源码,发现了Button跟ImageView的onTouchEvent都是在他们共同的父类实现的,但由于源码级别不够,所以做了下面这个实验
1.MyButton
public class MyButton extends android.support.v7.widget.AppCompatButton { public MyButton(Context context) { super(context); } public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } public MyButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("xx", "MyButton的onTouchEvent--" + event.getAction()); //super.onTouchEvent(event) return super.onTouchEvent(event); } }
2.MyImageView
public class MyImageView extends android.support.v7.widget.AppCompatImageView { public MyImageView(Context context) { super(context); } public MyImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("xx", "MyImageView的onTouchEvent--" + event.getAction()); //super.onTouchEvent(event) return super.onTouchEvent(event); } }
最后在activity_main里面使用
<com.example.yueyue.myapplication.widgte.MyButton android:text="Button" android:id="@+id/bt_click" android:textSize="12sp" android:textColor="#000" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <com.example.yueyue.myapplication.widgte.MyImageView android:id="@+id/iv_image" android:background="@mipmap/ic_launcher" android:layout_width="110dp" android:layout_height="110dp"/>
同时在Activity里面打印分发以及处理事件的方法
@Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i("xx", "MainActivity的dispatchTouchEvent" + ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i("xx", "MainActivity的onTouchEvent" + event.getAction()); return super.onTouchEvent(event); }
当你点击Button时候的情景:
I/xx: MainActivity的dispatchTouchEvent0
I/xx: MyButton的onTouchEvent–0
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MyButton的onTouchEvent–2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MyButton的onTouchEvent–2
I/xx: MainActivity的dispatchTouchEvent1
I/xx: MyButton的onTouchEvent–1
你会发现Button的onTouchEvent把DOWN,MOVE以及UP事件都消费了(事件作用在Button身上的时候)
当你点击ImageView时候的情景:
I/xx: MainActivity的dispatchTouchEvent0
I/xx: MyImageView的onTouchEvent–0
I/xx: MainActivity的onTouchEvent0
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent2
I/xx: MainActivity的onTouchEvent2
I/xx: MainActivity的dispatchTouchEvent1
I/xx: MainActivity的onTouchEvent1
这里可以看出,Button是默认可以点击的,ImageView是默认不可以被点击的,上源码
public boolean onTouchEvent(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); final int viewFlags = mViewFlags; final int action = event.getAction(); final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; //不可以被点击,就返回,不可以点击就不可以相应触摸事件以及点击事件 if ((viewFlags & ENABLED_MASK) == DISABLED) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return clickable; } //可以点击或者TOOLTIP事件可以走下面 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { switch (action) { case MotionEvent.ACTION_UP: mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; if ((viewFlags & TOOLTIP) == TOOLTIP) { handleTooltipUp(); } //不可被点击就会此结束 if (!clickable) { removeTapCallback(); removeLongPressCallback(); mInContextButtonPress = false; mHasPerformedLongPress = false; mIgnoreNextUpEvent = false; break; } //走到这里,说明clickable==true才可以到达这里,然后进行我们熟悉的MOVE,DOWN以及UP事件处理 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in // touch mode. boolean focusTaken = false; if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } if (prepressed) { // The button is being released before we actually // showed it as pressed. Make it show the pressed // state now (before scheduling the click) to ensure // the user sees it. setPressed(true, x, y); } if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { // This is a tap, so remove the longpress check removeLongPressCallback();//清除长按事件的回掉方法 // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick();//这里实现点击事件 } } } break; ... } return true;//clickable为true或者(viewFlags & TOOLTIP) == TOOLTIP)都会返回true,消费这件事 } return false; }
你会发现一个clickable为true就可以走到click事件啦,同时在这里也可以看出touch事件的UP事件才会触发click事件
1.Button默认消费全部事件(DOWN,MOVE以及UP事件),而ImageView不会
public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true);//为了让onTouch事件可以触发点击事件 } getListenerInfo().mOnClickListener = l; }
这里是View里面的源码,可以看出只要你注册了一个OnClickListener接口,那么你都是Clickable(可点击状态),或者你在xml文件中往组件添加 android:onClick=”“属性,那么该组件也是可点击状态啦,这样做都是为了为了让onTouch事件可以触发点击事件
这里阐述了一个问题:
if ((viewFlags & ENABLED_MASK) == DISABLED) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. //翻译:一个enable为false但clickable为true状态的视图依然可以消费事件,但它不会对他们相应(这里的他们值得是触摸事件) return clickable;//这里也解释了Button会把DOWN跟MOVE以及UP事件都消费的原因,但ImageView由于默认是不可以被点击的,所以不会消费任何的事件,最后只会返回一个FALSE(enable状态为false的时候) }
这里也可以看出一个知识点,
1.DOWN事件去确定消费者(可能是拦截,然后自己消费了该事件),然后MOVE以及UP分发过程中遇到消费者之后就不再向下传了,如果消费者不消费MOVE或者UP事件,那么就直接传给Activity去处理
2.分发过程中拦截的是DOWN事件(说明这时候还没有消费者),那么其本身的onTouch方法不消费,那么就上传给他的父亲(他父亲不消费,那么又上传给他爷爷),一层层上去直到找到消费者
3.分发过程中拦截的是MOVE事件或者UP事件,,如果其本身不消费MOVE或者UP事件,那么就直接传给Activity去处理,这里也解释了为什么拦截方法是在分发过程中进行拦截的,并且如果你在DOWN retrun true ,则DOWN,MOVE,UP子View都不会捕获事件(作为消费者,优先处理MOVE跟UP事件了);如果你在MOVE return true , 则子View在MOVE和UP都不会捕获事件。
原因很简单,当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ;
这样设计的目的我觉得是MOVE事件太多了,如果像DOWN事件这样回传,系统负荷太重了
推荐博客:
1.Android事件分发机制完全解析,带你从源码的角度彻底理解(上) - 郭霖的专栏 - CSDN博客 -浅显易懂
2.Android ViewGroup事件分发机制 - Hongyang - CSDN博客 -这个才是真正的源码级分析(最值得一看,虽然我看晕了)
3.Android中事件分发机制 - qq97206858的博客 - CSDN博客
————-我是低调的分割线————————–
如果对你有帮助,可以点击“推荐”哦`(*∩_∩*)′
相关文章推荐
- 关于ListView触摸事件和点击Item事件冲突解决方法
- Android中performClick方法---代码调用点击事件(模拟去触摸控件)
- 关于ListView触摸事件和点击Item事件冲突解决方法
- Android中Spinner控件关于二次点击同一item无响应事件解析及处理方法
- 简单讲解Android开发中触摸和点击事件的相关编程方法
- Android中View的触摸事件涉及到哪些方法?他们之间有什么关系?
- Android 触摸事件、点击事件的区别
- Android 实现事件监听的两个方法
- android ListView的OnItemClickListener事件被其内部Button点击事件屏蔽的解决方法
- android 触摸事件、点击事件的区别
- 在Android中ListView中添加两个点击事件,一个是OnItemClick,另一个是一个图片的OnClick事件
- Android中点击事件实现的四种方法
- 关于Android中popupwindow的listview的item点击事件无效的解决方案
- Android关于点击事件的特别处理
- Android开发之触摸事件-点击屏幕获…
- android事件传递机制,以及ondispatchEvent()、onInterceptTouchEvent()和OnTouchEvent()三个方法的作用关系
- android 触摸事件、点击事件的区别
- android中父view与子view关于触摸事件的理解
- 基于JQuery的span元素点击事件在windows7触摸上失效的解决方法
- 转:android触摸,点击事件区别