位置: 编程技术 - 正文

Android中的touch事件

编辑:rootadmin
Android中的事件

推荐整理分享Android中的touch事件,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

Touch事件,四种状态:

ACTION_DOWN ——> 表示按下了屏幕,一个事件必然从ACTION_DOWN开始ACTION_MOVE ——> 表示移动手势ACTION_UP ——> 表示离开屏幕ACTION_CANCEL ——> 表示取消手势,一般由程序产生,不会由用户产生

一个ACTION_DOWN, n个ACTION_MOVE,1个ACTION_UP,就构成了Android中众多的事件。

Android中的事件onClick, onScroll, onFling等等,都是由许多个Touch组成的。

一个原则,所有的touch事件都是从父容器开始向下传递的,呈U字形。

View事件处理机制核心代码

Android中诸如ImageView、textView、Button等控件都没有重写View的dispatchTouchEvent方法,所以View的事件处理机制对这些控件都有效。

View.java(基于android2.3.3):

[html] view plaincopypublic boolean dispatchTouchEvent(MotionEvent event) {//返回true,表示该View内部消化掉了所有事件。返回false,表示View内部只处理了ACTION_DOWN事件,事件继续传递,向上级View(ViewGroup)传递。 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {//此处的onTouch方式就是回调的我们注册OnTouchListener时重写的onTouch()方法 return true; } if (onTouchEvent(event)) {// onTouchEvent参考下面源码 return true; } ... }

[java] view plaincopypublic boolean onTouchEvent(MotionEvent event) { ... // 当前onTouch的组件必须是可点击的比如Button,ImageButton等等,此处CLICKABLE为true,才会进入if方法,最后返回true。 如果是ImageView、TexitView这些默认为不可点击的View,此处CLICKABLE为false,最后返回false。当然会有特殊情况,如果给这些View设置了onClick监听器,此处CLICKABLE也将为true,参考下面源码 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: ... if (!post(mPerformClick)) { performClick();// 实际就是回调了我们注册的OnClickListener中重新的onClick()方法,源码下面源码 } ... break; case MotionEvent.ACTION_DOWN: ... break; case MotionEvent.ACTION_CANCEL: ... break; case MotionEvent.ACTION_MOVE: ... break; } return true; } return false; }

[java] view plaincopypublic void setOnClickListener(OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; }

[java] view plaincopypublic boolean performClick() { ... if (li != null && li.mOnClickListener != null) { ... li.mOnClickListener.onClick(this); return true; } return false; }

总结:

只有我们注册OnTouchListener时重写的onTouch()方法中返回false ——> 执行onTouchEvent方法 ——> 导致onClick()回调方法执行

onTouch()方法返回true ——> onTouchEvent方法不执行 ——> 导致onClick()回调方法不会执行

ViewGroup事件处理机制核心代码

Android中诸如LinearLayout等的五大布局控件,都是继承自ViewGroup,而ViewGroup本身是继承自View,所以ViewGroup的事件处理机制对这些控件都有效。

ViewGroup.java(基于android2.3.3):

[java] view plaincopy@Override public boolean dispatchTouchEvent(MotionEvent ev) { ... if (action == MotionEvent.ACTION_DOWN) { if (mMotionTarget != null) { mMotionTarget = null; } //onInterceptTouchEvent返回false,说明向下传递 //onInterceptTouchEvent返回true,说明拦截 if (disallowIntercept || !onInterceptTouchEvent(ev)) { ... // 伪代码如下: //1,找到当前控件子控件 //2,判断当前touch的点的坐标(x,y)在哪个子控件的矩形区域内 //3,判断当前子控件是viewgroup的子类对象,还是view的子类对象 //3.1 如果是viewgroup的子类: 调用其dispatchTouchEvent方法,上述操作再来一遍 //3.2 view 尝试让当前view去处理这个事件( true,dispatchTouchEvent方法结束,并且返回true false,dispatchTouchEvent继续向下执行) ... } } ... target = mMotionTarget //target一定是null if (target == null) { ... //调用当前viewgroup的父View的处理事件的方法 return super.dispatchTouchEvent(ev); } ... }

[java] view plaincopypublic boolean onInterceptTouchEvent(MotionEvent ev) { return false;// 默认返回false }

总结:

1、dispatchTouchEvent作用:决定事件是否由onInterceptTouchEvent来拦截处理。

返回super.dispatchTouchEvent时,由onInterceptTouchEvent来决定事件的流向返回false时,会继续分发事件,自己内部只处理了ACTION_DOWN返回true时,不会继续分发事件,自己内部处理了所有事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP)

2、onInterceptTouchEvent作用:拦截事件,用来决定事件是否传向子View

返回true时,拦截后交给自己的onTouchEvent处理返回false时,拦截后交给子View来处理

3、onTouchEvent作用:事件最终到达这个方法

返回true时,内部处理所有的事件,换句话说,后续事件将继续传递给该view的onTouchEvent()处理返回false时,事件会向上传递,由onToucEvent来接受,如果最上面View中的onTouchEvent也返回false的话,那么事件就会消失

综合案例分析

以下摘自: view plaincopypublic class MainActivity extends Activity { Group1 group1; Group2 group2; MyTextView myTv; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //--group1 //----| //-------group2 //---------| //------------myTv group1 = new Group1(this); group2 = new Group2(this); myTv = new MyTextView(this); group2.addView(myTv, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); group1.addView(group2, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); setContentView(group1); } } Android中的touch事件

[java] view plaincopypublic class Group1 extends FrameLayout { public Group1(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group1 onInterceptTouchEvent触发事件:"&#;Constant.getActionTAG(ev.getAction())); return false; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group1 onTouchEvent触发事件:"&#;Constant.getActionTAG(event.getAction())); return false; } }

[java] view plaincopypublic class Group2 extends FrameLayout { public Group2(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group2 onInterceptTouchEvent触发事件:"&#;Constant.getActionTAG(ev.getAction())); return false; } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "Group2 onTouchEvent触发事件:"&#;Constant.getActionTAG(event.getAction())); return false; } }

[java] view plaincopypublic class MyTextView extends TextView { public MyTextView(Context context) { super(context); this.setGravity(Gravity.CENTER); this.setText("点击我!"); // TODO Auto-generated constructor stub } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub Log.d(Constant.LOGCAT, "MyTextView onTouchEvent触发事件:"&#;Constant.getActionTAG(event.getAction())); return false; } }

[java] view plaincopypublic class Constant { public static final String LOGCAT = "logcat"; public static String getActionTAG(int action) { switch (action) { case 0: return "ACTION_DOWN"; case 1: return "ACTION_UP"; case 2: return "ACTION_MOVE"; default: return "NULL"; } } }

分别重写Group1和Group2的onInterceptTouchEvent和onTouchEvent方法,重写MyTextView的onTouchEvent方法,最终得到的控件层次结构如下:

1.在默认返回&#;情况下logcat输出如下:

测试后可知默认情况下和所有方法返回&#;为false的结果一致,down事件的捕获顺序onInterceptTouchEvent先于onTouchEvent,由于onTouchEvent返回&#;为false,down事件没被消化,后续的move和up事件没有出现,同时逆序返回到父控件的onTouchEvent方法来捕获,如下图所示:

2.所有onTouchEvent返回&#;为true情况下logcat输出如下:

输出结果可以看出子控件MyTextView消化了down事件,后续的move和up事件正常捕获,由于down事件被消化,上层的onTouchEvent方法不执行,如下图所示:(三箭头分别指down、move、up事件)

既然如此,如果MyTextView中onTouchEvent方法返回为false,而group1和group2的onTouchEvent方法返回true的结果自然也就如下图的顺序了:

测试输出结果证明了这一猜测顺序:

注意:可能有人对这种情况比较疑惑,ACTION_DOWN还好理解,但是ACTION_MOVE为什么没有经历myTv,而且ACTION_MOVE只经历了group1的onInterceptTouchEvent和group2的onTouchEvent而没有经历group2的onInterceptTouchEvent?我开始也费解,后来想想也是,大家对比第1条,由于onTouchEvent返回了false而没有消耗down事件导致后续的move和up都没有出现,这里也是一样由于myTv中onTouchEvent返回了false也就是说没有消耗down事件,那么后面的move和up也都不会出在这个view里面,但是group2截获到了down事件,但后来的move为什么group2中的onInterceptTouchEvent没有执行到呢,原因大家不要忘记了onInterceptTouchEvent的初衷是什么,返回false是让它的子view或viewgroup类处理,而group2的子控件显然是myTv而myTv的onTouchEvent返回了false也就是接收不到后续的move和up事件,也就没必要经过onInterceptTouchEvent来继续分发了(因为分发了也还是接收不到),经过group2的onTouchEvent因为它返回的是true,截获了事件并且消耗了事件。

3.当某个GroupView中的onInterceptTouchEvent方法返回&#;为true情况下logcat输出如下(如group2):

如果在该方法返回&#;中返回true,那么子控件将获取不到任何点击事件,转而向自身的onTouchEvent方法转发,如下图所示:

如果onTouchEvent方法返回&#;都为true,那么根据规律结果就如下图顺序触发:

最后logcat的结果证实了这一猜测:

还有一篇文章也比较好,可作为这个案例的补充,

欢迎使用CSDN-markdown编辑器 AndroidStudio下几个使用的快捷键-快速生成方法:Ctrl+Alt+M-快速选择代码块:Ctrl+Up/Down–重命名:Shift+F6:–快速将变量设置全局变量:Ctrl+Alt+C:–快速添加

Android快速使用SharedPreferences 保存配置/***保存相关设置*/publicvoidsaveSharedPreferences(){//1.得到编辑器,"config"为保存的文件名,若没有则新建SharedPreferences.EditormEditor=mContext.getSharedPreferen

Android消息队列模型 Google官方给Handler的解释如下:AHandlerallowsyoutosendandprocessMessageandRunnableobjectsassociatedwithathread'sMessageQueue.EachHandlerinstanceisassociatedwithasinglethreadandthatthread'smes

标签: Android中的touch事件

本文链接地址:https://www.jiuchutong.com/biancheng/370959.html 转载请保留说明!

上一篇:android recycleView(android RecycleView 面试)

下一篇:欢迎使用CSDN-markdown编辑器(欢迎使用来电提醒业务,本次呼叫将以点对点)

  • 金税开票软件怎么修改开票人
  • 纳税人识别号怎么看是不是一般纳税人
  • 房地产企业递延所得税资产计算方法
  • 牵引车和挂车都要购买交强险吗
  • 开了发票不做收入的账务处理
  • 控股收益
  • 营业外支出罚款所得税怎么处理
  • 坏账核销计入营业利润吗
  • 借支单是借方还是贷方
  • 眼镜所属行业怎么填写
  • 抵缴以前年度多缴所得税如何做会计分录?
  • 筹备费用怎么扣税的
  • 开错税率怎么报税
  • 分公司背书给总公司
  • 销项在借方还是贷方
  • 审计风险可控吗
  • 出口收入转内销后汇率
  • 小规模纳税人已经开了3%的票还可以享受1%的优惠吗
  • 航天金税盘费用怎么做账
  • 暂估收入销项税与后期开票不一致
  • 个税滞纳金如何调增所得税费用
  • 红冲发票显示发票状态不正常
  • 事业单位固定资产报废处置流程
  • 利润表没有其他业务利润
  • win 11bug
  • 货款已经收到
  • 企业为开发新产品新技术新工艺
  • 丢失空白发票怎么处罚
  • 高新技术企业研发人员比例要求
  • 未开票收入缴纳增值税怎么冲减补开发票
  • win10怎么关掉
  • 对数据文件操作,进行数据记录的交换都要经过
  • thinkphp怎么部署
  • 商场外面的广告牌叫什么
  • php自动下载文件到本地
  • 停止恶意软件删除怎么办
  • 民办学校的财务制度
  • 期间费用为什么叫期间费用
  • file php
  • 转回已核销的坏账
  • 销售自行开发的房地产
  • 委托加工应税消费品以委托人为消费税的纳税义务人
  • 用友财务软件使用视频教程
  • 微信支付开发步骤
  • thinkphp怎么用
  • 存货报废如何处理方案
  • 贷款 减值
  • react高阶组件
  • 公账转钱出来要收手续费吗
  • 营业总成本包括投资收益吗
  • mysql常用命令有哪些
  • 先销售后开发票的如何做帐?
  • 企业所得税的减免税额
  • 残保金需要计提吗怎样做分录
  • 增值税处罚条例
  • 应付职工薪酬的核算内容
  • 固定资产清理的累计折旧怎么算
  • 会计科目中其期末余额应列入资产负债表存货项目的有
  • 银行存款利息记账凭证
  • 服务业收入的会计分录
  • 财务人员怎么查出发票虚开?
  • win8的系统怎么装win7
  • 防盗信息
  • Ubuntu系统怎么设置IP
  • xp局域网文件共享设置
  • win7系统电脑无限重启
  • 文件属性命令
  • Win7注册表怎么恢复命令
  • windows7开机启动
  • ubuntu 软件删除
  • 安卓手机好用的笔记类app
  • 清除电脑开机痕迹
  • 使用vue-cli快速搭建vue项目
  • document.write与writeln的输出内容区别说明
  • 尽有可能的拼音
  • 重庆市电子发票样式
  • 季度企业所得税分录
  • 怎么打印电子社保
  • 小规模纳税人开3%专票怎么交税
  • 增值税税控开票软件怎么下载
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设