这个问题,当初在分析touch事件处理的时候按理应该分析到的,可是由于我当时觉得这块代码和touch的主题不是那么紧密,

就这么忽略掉了,直到后来在这上面遇到了问题。其实这个现象做Android开发的应该或多或少的都遇到过,我在我们自己的app中

也发现了这一现象,当初是百思不得其解,因为按照我自己的研究、分析,只有在一个view接受按下的touch事件时,才会调到view

自己的setPressed方法,从而改变background状态啊。这里的case明显没有按下这个子view啊,按下的是ViewGroup啊,所以一直

没想通,当时也就没多想,就这么不明不白的过去了(现在回过头来想,其实只要在android src中搜索下setPressed方法都在哪调用了,

这个问题就迎刃而解了)。直到有一天,我们的公司的Review中又再次遇到了相关的问题,巧合的是我们的这个fix把原先的bug解了,但

不幸的是引入了本文的这个问题。问题又一次出现了,同时我们的另一名同事给我看了段ViewGroup里的代码,我当时的第一感觉是又兴奋

又惊讶。兴奋是困扰我许久的问题终于有答案了,惊讶是不太能理解为啥Android会写这样一段在我看来有点“多管闲事”的代码。好了,故事

背景交代的差不多了,下面直接进入主题。

  对touch事件有了解的同学大体都知道,View.setPressed(true)调用发生在View.onTouchEvent方法中,视情况不同要么是DOWN

事件、或者DOWN事件推迟TAP_TIMEOUT毫秒之后,要么是UP事件处理的时候。我们来看下相关源码:

    /**
* Sets the pressed state for this view.
*
* @see #isClickable()
* @see #setClickable(boolean)
*
* @param pressed Pass true to set the View's internal state to "pressed", or false to reverts
* the View's internal state from a previously set "pressed" state.
*/
public void setPressed(boolean pressed) {
// 检查pressed状态是否改变
final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); if (pressed) { // 设置标志位
mPrivateFlags |= PFLAG_PRESSED;
} else {
mPrivateFlags &= ~PFLAG_PRESSED;
} if (needsRefresh) { // 状态改变了,那么需要刷新下drawable state,在这里background会变成合适的样子
refreshDrawableState();
}
dispatchSetPressed(pressed); // 将pressed状态传递到子view
} /**
* Dispatch setPressed to all of this View's children.
*
* @see #setPressed(boolean)
*
* @param pressed The new pressed state
*/
protected void dispatchSetPressed(boolean pressed) { // view的默认是do nothing,因为它也没children啊
} // ViewGoup对dispatchSetPressed的重载
@Override
protected void dispatchSetPressed(boolean pressed) { // 这是ViewGroup对其的实现
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = 0; i < count; i++) {
final View child = children[i];
// Children that are clickable on their own should not
// show a pressed state when their parent view does.
// Clearing a pressed state always propagates. 注意理解这段注释
if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
// 其实这个if主要是做了2件事,1如果pressed是false则总是调用child的setPressed(false)方法,也就是说这种
// 情况下always传递;2如果pressed是true,则只有child不能响应touch事件即clickable、longClickable都是false
// 的时候才调用child.setPressed(true)方法。说白了,child自己能处理pressed事件则他们自己会处理,否则parent会
// 强迫child处理。同时注意下,这个调用还是递归的,会一直传递给子孙后代。。。
child.setPressed(pressed);
}
}
}

  另外需要提1点就是直到Android4.1.x开始ViewGroup.dispatchSetPressed方法才在遍历children时加了这个if判断,也就是说之前

的版本会直接调用child.setPressed(pressed)方法。从上面的分析可以看出,由于这里parent“强迫”child处理pressed事件,所以为了避

免出现本文一开始的现象(或者叫bug),你有2种方式:

1. 让某个view自己能处理touch事件,也即设置clickable、longClickable为true;

2. 如果某个view自己不处理touch事件,那么你就不应该给它设置个stateful的drawable,或者至少不应该给它pressed状态设置一个单独

的drawable,这样即使发生了setPressed(true)调用,也没关系。

我们代码里,选用了第2种解决方式,直接在代码中去掉了其background。这篇小文章算是对前面touch事件处理的补充也是开发过程中的

经验、教训,希望对大家有所帮助,enjoy。。。

  最后,附上一篇csdn的同主题文章:http://blog.csdn.net/cpyyes/article/details/11144497

点击ViewGroup时其子控件也变成pressed状态的原因分析及解决办法的更多相关文章

  1. 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法

    本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...

  2. 浅析:点击父控件时,子控件中的textview自动进入选中状态

    原因:父控件属性android:clickable="true",而textview之类的自控件默认不可点击,没有独立的点击监听,这样选中父控件时,textview之类的子控件也进 ...

  3. bootstrop 日期控件 datepicker被弹出框dialog覆盖的解决办法

    筒子们在使用bootstrap的日期控件(datepicker , 现在官网提供的名称叫 datetimepicker)时可能会遇到如上图的问题这是啥原因造成的呢? 答案很简单时输出的优先级造成的(z ...

  4. phpcmsV9中表单向导在js调用里日期控件在IE下报Calendar未定义的解决办法

    最近在phpcmsV9里用表单向导弄个的提交表单,但用了日期和时间类型时,用   <script language='javascript' src='{APP_PATH}index.php?m ...

  5. 简述Object(ActiveX)控件遮挡Dialog、select下拉框的解决办法

    1.背景 最近在做项目的过程中,我们使用了Object控件,但是同时在上面写了一个select下拉框,因此每次点击下拉框的时候我们会发现,下拉框的部分内容被Object控件给遮挡了,调查研究后发现,我 ...

  6. VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误

    1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...

  7. 【C#】在窗体中水平居中的控件,到了XP下不居中的解决办法

    我时不时会遭遇这个操蛋问题,今天得闲研究了一下,解决如下: A.将窗体FormBorderStyle属性改为Fixed系,当然这会导致用户不能拖拉窗口大小,所以你可能需要B计划↓ B.确保在[VS]中 ...

  8. MJ刷新控件MJRefreshFooterView上拉之后收不回来的解决办法

    修改MJRefreshFooterView.m文件中的这个方法 #pragma mark - 状态相关 #pragma mark 设置状态 - (void)setState:(MJRefreshSta ...

  9. Nested Loops join时显示no join predicate原因分析以及解决办法

    本文出处:http://www.cnblogs.com/wy123/p/6238844.html 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据, ...

随机推荐

  1. DIV元素水平和垂直居中

    在前端开发过程中,经常要对元素进行居中设置.一般有水平居中,和垂直居中.一般设置水平居中简单.基本是margin:0 auto,就可以了.但是垂直居中,我们有时会觉得使用vertical-align, ...

  2. C#:根据银行卡卡号判断银行名称

    原文地址:android 根据银行卡卡号判断银行 原文是 java ,现在将它翻译成 C# ,并对代码重新编排整理,博主是一个今年刚出来的应届毕业生,不足之处请多多包涵. 根据银行卡号判断所属银行,依 ...

  3. 高级javascript---原型和原型继承

    高级javascript---原型和原型继承 在 JavaScript 中,prototype 是函数的一个属性,同时也是由构造函数创建的对象的一个属性. 函数的原型为对象. 它主要在函数用作构造函数 ...

  4. 设计窘境:来自 Repository 的一丝线索,Domain Model 再重新设计

    写在前面 阅读目录: 疑惑解读 设计窘境 一幅图的灵感 为嘛还是你-Repository 后记 上一篇<No zuo no die:DDD 应对具体业务场景,Domain Model 重新设计& ...

  5. golang开发环境配置及Beego框架安装

    配置环境:Windows7推荐IDE:LiteIDEGO下载地址:http://www.golangtc.com/downloadBeego开发文档地址:http://beego.me/docs/in ...

  6. C#运用GmaQrCode生成二维码

    项目中需要生成二维码,方法比较多,可以采用JS插件,也可以采用第三方插件后台生成二维码,在后台方法中可以采用QRCode或者GmaQrCode,现在介绍一种C#在后台生成二维码的方法: /// < ...

  7. 浅谈2D游戏设计模式3 - 冒险地图之美(1)

    冒险岛之所以能长久的存在,很大一部分原因是因为它的美工设计的非常的精细,以及独特,那么独特以及美究竟体现在哪些方面呢? 今天我就带大家来分析几幅地图吧. 好吧,我们就拿上面这幅美景来分析吧. 1.阳光 ...

  8. .NET 内存基础(通过内存体验类型、传参、及装箱拆箱)

    该随笔受启发于<CLR Via C#(第三版)>第四章4.4运行时的相互联系 一.内存分配的几个区域 1.线程栈 局部变量的值类型 和 局部变量中引用类型的指针(或称引用)会被分配到该区域 ...

  9. sql 2012中获取表的信息,包含字段的描述

    1.获取数据库中的表 select name from sysobjects where type='U' 2.获取表字段(此处是Route表) Select name from syscolumns ...

  10. 【转】asp.net(c#)加密解密算法之sha1、md5、des、aes实现源码详解

    原文地址:http://docode.top/Article/Detail/10003 目录: 1..Net(C#)平台下Des加密解密源代码 2..Net(C#)平台下Aes加密解密源代码 3..N ...