为什么要说这个问题呢,这段时间还是在SeekBar上遇到一些问题,好像ADT并没有给seekBar在xml中提供enabled属性,虽然我们可以在代码中设置,但是它并不能实现下面这个需求,所以我们需要找到别的方式去实现它,也为了能更好的了解一下dispatchTouchEvent与onTouchEvent之间的关系。

我们现在有这么一个问题,我们需要使SeekBar在某些时候只可点击不可拖动,如果简简单单使用enabled的话,那么只会不能移动,这是不满足的。所以我们需要有这么一个入口去逐步解决这个问题。

入口点:

需要知道seekbar是如何拖动与绘制的。

首先会想到去哪找这个问题?肯定是SeekBar的onTouchEvent方法对不对?我们在拖拽seekBar的thumb的时候,肯定会触发MotionEvent.ACTION_MOVE的事件,这样一来,我们就找到了我们问题当然入口处,只用合理控制onTouchEvent方法的调用就可以了,我们从源码开始看:

在SeekBar类中是没有onTouchEvent方法的,那么我们需要去它的父类中找,如果父类中没有,那么就需要去父类的父类中去找,直到找到为止,那么我们很快的就在SeekBar的父类AbsSeekBar中找到了onTouchEvent方法:

    public boolean onTouchEvent(MotionEvent event) {if (!mIsUserSeekable || !isEnabled()) {return false;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (isInScrollingContainer()) {mTouchDownX = event.getX();} else {setPressed(true);if (mThumb != null) {invalidate(mThumb.getBounds()); // This may be within the padding region}onStartTrackingTouch();trackTouchEvent(event);attemptClaimDrag();}break;case MotionEvent.ACTION_MOVE:if (mIsDragging) {trackTouchEvent(event);} else {final float x = event.getX();if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {setPressed(true);if (mThumb != null) {invalidate(mThumb.getBounds()); // This may be within the padding region}onStartTrackingTouch();trackTouchEvent(event);attemptClaimDrag();}}break;case MotionEvent.ACTION_UP:if (mIsDragging) {trackTouchEvent(event);onStopTrackingTouch();setPressed(false);} else {// Touch up when we never crossed the touch slop threshold should// be interpreted as a tap-seek to that location.onStartTrackingTouch();trackTouchEvent(event);onStopTrackingTouch();}// ProgressBar doesn't know to repaint the thumb drawable// in its inactive state when the touch stops (because the// value has not apparently changed)invalidate();break;case MotionEvent.ACTION_CANCEL:if (mIsDragging) {onStopTrackingTouch();setPressed(false);}invalidate(); // see above explanationbreak;}return true;}

来分析下这段代码:

mIsUserSeekable在AbsSeekBar中声明为了true,后面也没有任何地方对它进行修改。isEnabled由于没有对它进行专门设置,所以这里恒为true。所以if中的判断恒为false。接着往下MotionEvent.ACTION_DOWN中的if(isInScrollingContainer())表示是说如果是在可以滚动的容器当中,我们这里使用的是平常的布局,所以这里为false。

setPressed(true)更改按压状态,invalidate(mThumb.getBounds())绘制thumb,onStartTrackingTouch设置mIsDragging为true为ACTION_MOVE做准备,trackTouchEvent对内部进行测量计算绘制界面,attemptClaimDrag禁止父布局及祖先布局阻断touch事件。好,接下来就是MotionEvent.ACTION_MOVE了,已知mIsDragging是true,所以当执行move的时候一直是在调用trackTouchEvent方法了,所以,我们在拖拽的seekBar的thumb的时候就是在这里进行的处理。好,有些扯远了,回到我们的主要部分:

我们刚刚可以看到onTouchEvent中没有任何一处可以对我们的触摸事件进行拦截,那我们就需要找在哪里调用了onTouchEvent方法,我们从SeekBar到其父类AbsSeekBar再到ProgressBar,最后到View的dispatchTouchEvent中被调用了:

    /*** 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) {boolean result = false;if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onTouchEvent(event, 0);}final int actionMasked = event.getActionMasked();if (actionMasked == MotionEvent.ACTION_DOWN) {// Defensive cleanup for new gesturestopNestedScroll();}if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {result = true;}if (!result && onTouchEvent(event)) {result = true;}}if (!result && mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);}// Clean up after nested scrolls if this is the end of a gesture;// also cancel it if we tried an ACTION_DOWN but we didn't want the rest// of the gesture.if (actionMasked == MotionEvent.ACTION_UP ||actionMasked == MotionEvent.ACTION_CANCEL ||(actionMasked == MotionEvent.ACTION_DOWN && !result)) {stopNestedScroll();}return result;}

我们先不管其它,只关心我们关心的:

        if (onFilterTouchEventForSecurity(event)) {//noinspection SimplifiableIfStatementListenerInfo li = mListenerInfo;if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {result = true;}if (!result && onTouchEvent(event)) {result = true;}}

我们先不管外面那个方法,只看 内部:这里判断了li.mOnTouchListener是否为空,控件是否可用,最后通过mOnTouchListener.onTouch将事件传递进去,这里的返回值就很关键了,如果返回false,则代码会继续向下执行,最后交给onTouchEvent,如果返回true,则直接返回,不会再执行onTouchEvent方法。所以为了解决有时可以点击SeekBar,但又不能拖拽问题,我们就可以从mOnTouchListener下手了。

从源码说说dispatchTouchEvent与onTouchEvent的关系以及OnTouchListener的用法相关推荐

  1. ubuntu中手动编译源码安装Xorg-server过程中依赖关系的解决

    ubuntu中手动编译源码安装Xorg-server过程中依赖关系的解决 在linux系统中手动编译源码安装软件包的过程是非常痛苦的,然而这一个多星期以来我是强忍住脾气体验了一把,虽然面对慢的令人发指 ...

  2. 浅析微信头脑王者答题小程序源码功能模块与价格之间关系

    随着移动互联网的发展,微信小程序开发日渐成熟.答题小程序头脑王者源码的出现大大的方便了人们的生活.也为部分企业带来了很大的利益,正是因为这样越来越多的企业都会选择去开发一个微信答题小程序自己以来更多的 ...

  3. 【附源码】计算机毕业设计java银行客户关系管理系统设计与实现

    项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...

  4. 黄聪:wordpress源码解析-目录结构-文件调用关系(转)

    Wordpress是一个单入口的文件,所有的前端处理都必须经过index.php,这是通过修改web服务器的rewrite规则来实现的.这种做法的好处是显而易见的,这样URL更好看,不必为每一个url ...

  5. View事件分发机制(源码分析篇)

    01.Android中事件分发顺序 1.1 事件分发的对象是谁 事件分发的对象是事件.注意,事件分发是向下传递的,也就是父到子的顺序. 当用户触摸屏幕时(View或ViewGroup派生的控件),将产 ...

  6. Android View体系(五)从源码解析View的事件分发机制

    Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Sc ...

  7. Android事件分发之ViewGroup篇 -- ViewGroup的dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent之间关系

    Android事件分发之ViewGroup篇(FatherViewGroup) – ViewGroup的dispatchTouchEvent.onTouchEvent.onInterceptTouch ...

  8. Android Touch事件分发(源码分析)

    Android一文让你轻松搞定Touch事件分发 源码分析 下面,咱们一起通过源码,全面解析事件分发机制,即按顺序讲解: Activity事件分发机制 ViewGroup事件分发机制 View事件分发 ...

  9. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

最新文章

  1. 解决Android Studio中DDMS缺少File Explore视窗的方法
  2. 使用uglify不能压缩的一些js语法(持续发现中)
  3. 【SQL】使用调用层接口
  4. Python--set集合讲解; 什么是集合?创建一个集合;集合的操作函数;
  5. python中怎么输入角度_在Python中更正两点之间的角度
  6. MAUI中构建跨平台原生控件实现
  7. open、read、write、文件类型
  8. 2019-03-28 SQL Server Pivot
  9. linux putty 字体,putty修改字体配色
  10. github出现Your account has been flagged.导致账号无法公开的解决办法
  11. Android5.1自定义闹钟铃声,Android 设置来电铃声、通知铃声、闹钟铃声中的坑
  12. CheckBox的Attributes
  13. “5G 时代,手机或被淘汰”
  14. 终于搞懂了Java 8 的内存结构,再也不纠结方法区和常量池了!!
  15. 使用企业邮箱的好处优点
  16. 运营商级ICT项目建设之雪亮工程方案,提升群众安全感
  17. android中接口的作用是什么意思,Type-C接口有什么好处?和安卓micro USB接口有什么区别...
  18. C语言实现格林威治时间转北京时间+根据日期计算星期几
  19. Codeforces Round #555 (Div. 3), problem: (C2) Increasing Subsequence (hard version)【贪心+撞到南墙也不回头】
  20. jlink烧写linux内核,如何利用JLINK烧写U-boot到NAND Flash中

热门文章

  1. DIY一个低成本多功能点阵时钟!
  2. 你真的理解内存分配吗?
  3. 单片机的引脚,你都清楚吗?
  4. recovery模式下支持ADB连接和串口操作
  5. pC机OracLe库磁盘坏如何恢复,电脑硬盘坏了数据能恢复吗(6步教你自己在家轻松恢复数据)...
  6. python barrier_Python线程障碍对象Barrier原理详解
  7. c语言编辑的库存管理软件,C语言课程设计,商品库存管理系统怎么做啊?
  8. mit数据集_DriveSeg:动态驾驶场景分割数据集
  9. python批量访问网页保存结果_Python检测批量URL状态,并将返回正常的URL保存文件...
  10. 智慧交通day03-车道线检测实现09:车道线检测代码汇总(Python3.8)