Android 中触摸事件与点击事件分析
来源:互联网 发布:手机淘宝申请退款在哪 编辑:程序博客网 时间:2024/05/22 12:41
触摸事件
两种检测触摸事件的方式:
- 设置触摸监听 setOnTouchListener
返回 true: 表示消费事件 , 可以检测到 down/move/up 事件返回 false: 不消费事件, 只能检测到 down 事件
- 重写onTouchEvent()
必须继承自系统的一个View,才能重写 onTouchEvent()方法;如 MyImageView extends ImageView ,才能重写onTouchEvent返回 true: 消费事件,能检测到 down/move/up 事件返回 false: 不消费事件,只能检测到 down 事件
如果两种触摸事件都存在,并且都返回true,结果如何?
setOnTouchListener 有效onTouchEvent() 无效
另外:一个View能否消费事件,关键看 dispatchTouchEvent(),我们来看下 android-10的源码(为什么要看这个版本的源码呢?因为低版本的源码中,原理性的知识点都是一样的,高版本的源码中,加入了非常多的逻辑判断)View.java事件是怎么分发的
/** * Pass the touch screen motion event down to the target view, or this * view if it is the target. * * @param event The motion event to be dispatched. * @return True if the event was handled by the view, false otherwise. */ public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
我们可以看到如果两种方式都设置的话,每次这个if条件判断都会走,所以 onTouchListener 可以拿到所有事件(down/move/up事件);只有onTouchListener返回false时,onTouchEvent()方法才会走,才能拿到(down/move/up)所有事件;
如何让两种方式同时生效呢?
setOnTouchListener 返回falseonTouchEvent() 返回true
下面我们上代码:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.xialm.touchdemo.MainActivity"> <ImageView android:id="@+id/iv" android:layout_width="100dp" android:layout_height="100dp" android:src="@mipmap/ic_launcher" /></RelativeLayout>
修改返回true,所有事件都能拿到;返回false,只能拿到down事件;
true时:
04-28 01:44:13.515 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 004-28 01:44:18.266 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:44:18.283 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:44:18.333 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:44:19.555 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 1
false时:
04-28 01:44:13.515 1471-1471/com.xialm.touchdemo E/MainActivity: onTouch: 0
同理,我们创建 CustomImageView,继承自ImageView,同时修改布局文件中的ImageView为 CustomImageView
public class CustomImageView extends ImageView { private static final String TAG = "CustomImageView"; public CustomImageView(Context context) { super(context); } public CustomImageView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 返回false:只能拿到down事件 * 返回true: 能拿到down/move/up事件 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "onTouchEvent: "+event.getAction() ); return true; //super.onTouchEvent(event); }}同时设置,同时返回true的情况,可以看到跟我们的分析是一样的
04-28 01:47:54.060 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 004-28 01:47:54.434 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:47:54.450 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:47:54.817 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:47:54.850 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:47:55.188 5005-5005/com.xialm.touchdemo E/MainActivity: onTouch: 1
同时设置setOnTouchListener返回false,onTouchEvent()返回true
04-28 01:49:55.452 6978-6978/com.xialm.touchdemo E/MainActivity: onTouch: 004-28 01:49:55.452 6978-6978/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 004-28 01:49:58.850 6978-6978/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:49:58.850 6978-6978/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 01:49:58.866 6978-6978/com.xialm.touchdemo E/MainActivity: onTouch: 204-28 01:49:58.866 6978-6978/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 01:49:59.926 6978-6978/com.xialm.touchdemo E/MainActivity: onTouch: 104-28 01:49:59.926 6978-6978/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 1
Touch事件处理流程分析
我们自定义一个MyLinearLayout 继承自系统的LinearLayout,然后在布局文件中包裹 CustomImageView,
public class MyLinearLayout extends LinearLayout { private static final String TAG = "MyLinearLayout"; public MyLinearLayout(Context context) { super(context); } public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "onTouchEvent: "+event.getAction() ); return true;//super.onTouchEvent(event); 返回true }}
<com.xialm.touchdemo.MyLinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ccc" android:padding="10dp"> <com.xialm.touchdemo.CustomImageView android:id="@+id/iv" android:layout_width="100dp" android:layout_height="100dp" android:src="@mipmap/ic_launcher" /> </com.xialm.touchdemo.MyLinearLayout>
我们只研究onTouchEvent()
CustomImageView的onTouchEvent()也返回true
04-28 02:37:15.952 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 004-28 02:37:16.350 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:37:16.367 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:37:16.700 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:37:17.367 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:37:17.648 14101-14101/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 1当父View和子view都有处理触摸事件的逻辑时,子view可以接收到所有的事件;
这是因为事件传递是由外向内,而事件的消费是由内向外的;
只有子View不处理触摸事件时,父View才能处理消费事件(即CustomImageView的onTouchEvent()返回false,MyLinearLayout的onTouchEvent()返回true)
使用下面示意图来解释,再好不过了:
父View想要消费事件,有没有办法呢?办法是有的,只需重写onInterceptTouchEvent()方法,返回true,把事件中断掉,则事件就不能往下传递了,我们处理消费逻辑即可:public class CustomImageView extends ImageView { ...省略代码... /** * 返回false:只能拿到down事件 * 返回true: 能拿到down/move/up事件 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "onTouchEvent: "+event.getAction() ); return true; //super.onTouchEvent(event); }}public class MyLinearLayout extends LinearLayout { ...省略代码... private int count = 0; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { count++; if (count > 4) { return true; } return false; // 中断事件 } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "onTouchEvent: "+event.getAction() ); return true;//super.onTouchEvent(event); }}04-28 02:52:30.948 28332-28332/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 004-28 02:52:31.250 28332-28332/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:52:31.266 28332-28332/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:52:31.783 28332-28332/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 204-28 02:52:31.800 28332-28332/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 304-28 02:52:31.867 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:31.933 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:31.950 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:32.033 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:32.050 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:32.167 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 204-28 02:52:35.396 28332-28332/com.xialm.touchdemo E/MyLinearLayout: onTouchEvent: 1由下面流程示意图来说明:
触摸事件与点击事件
onTouchEvent() 与 onClickListener
点击事件是由 down 和 up 事件组成的,系统一直检测 up事件是否发生,如果有up事件,就会判断 onClickListener监听是否存在,存在就回调onClick()方法
触摸事件和点击事件同时存在时:
系统是怎么区分点击事件还是触摸事件呢?不知道你有没有注意到我们重写onTouchEvent()时有一句话super.onTouchEvent(event); // 在内部处理了,点击事件的逻辑
查看android-10 View.java源码 我们着重留意一下 up事件/** * Implement this method to handle touch screen motion events. * * @param event The motion event. * @return True if the event was handled, false otherwise. */ public boolean onTouchEvent(MotionEvent event) { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: // 着重研究up事件 if ((mPrivateFlags & PRESSED) != 0) { // 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 (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } // Only perform take click actions if we were in the pressed state if (!focusTaken) { performClick(); // 执行点击监听回调 } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (!post(mUnsetPressedState)) { // If the post failed, unpress right now mUnsetPressedState.run(); } } break; case MotionEvent.ACTION_DOWN: mPrivateFlags |= PRESSED; refreshDrawableState(); if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) { postCheckForLongClick(); } break; case MotionEvent.ACTION_CANCEL: mPrivateFlags &= ~PRESSED; refreshDrawableState(); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); // Be lenient about moving outside of buttons int slop = ViewConfiguration.get(mContext).getScaledTouchSlop(); if ((x < 0 - slop) || (x >= getWidth() + slop) || (y < 0 - slop) || (y >= getHeight() + slop)) { // Outside button if ((mPrivateFlags & PRESSED) != 0) { // Remove any future long press checks if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } // Need to switch from pressed to not pressed mPrivateFlags &= ~PRESSED; refreshDrawableState(); } } else { // Inside button if ((mPrivateFlags & PRESSED) == 0) { // Need to switch from not pressed to pressed mPrivateFlags |= PRESSED; refreshDrawableState(); } } break; } return true; } return false; }/** * Call this view's OnClickListener, if it is defined. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ public boolean performClick() { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); if (mOnClickListener != null) { // 点击监听回调不为null,就执行回调,并返回true playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; }如果我们想要同时处理点击事件和触摸事件,super.onTouchEvent(event); 就不可少@Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); Log.e(TAG, "onTouchEvent: "+event.getAction() ); return true; }04-28 03:40:08.296 8330-8330/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 004-28 03:40:08.392 8330-8330/com.xialm.touchdemo E/CustomImageView: onTouchEvent: 104-28 03:40:08.393 8330-8330/com.xialm.touchdemo E/MainActivity: onClick:
0 0
- Android 中触摸事件与点击事件分析
- android点击事件与触摸事件
- Android触摸事件与点击事件的区别
- android随笔24——触摸事件与点击事件
- Android触摸事件与点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- Android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- Android 触摸事件、点击事件的区别
- android 触摸事件、点击事件的区别
- Android 触摸事件、点击事件的区别
- 深入分析Android触摸事件
- finished with non-zero exit value 2
- 分布式系统事务一致性解决方案
- 学习C++从入门到精通的十本最经典书籍
- aop 正则表达式
- 深度学习史上最全总结(文末有福利)
- Android 中触摸事件与点击事件分析
- Vijos 1785题:同学排序
- 【python】解决linux下unzip乱码问题
- 深入理解linux系统下proc文件系统内容
- 最后一帖
- Native C++ via CLR/C++到C#(一)
- 真的,关于深度学习与计算机视觉,看这一篇就够了 | 硬创公开课
- 重识OkHttp:从深入了解到源码分析
- python-环境搭建及自动化测试Demo
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
上海美术馆
上海历史
上海长宁
上海世博会
上海人
上海旅行
上海徐家汇
上海普陀
上海公园
上海静安
上海公交app
上海英文
上海汽车站
上海海洋馆
上海有海吗
天津到上海
上海名校
上海好吗
上海海拔
上海教育网
上海牌照
成都到上海
上海明星
上海照片
上海漫展
上海位置
上海图
上海新楼盘
上海建筑
上海魔都
上海新房网
上海到西塘
上海小吃街
上海政法
上海东站
南昌到上海
上海车管所
上海gdp
上海工资
苏州到上海
上海旅馆