点击ViewGroup时其子控件也变成pressed状态的原因分析及解决办法
这个问题,当初在分析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状态的原因分析及解决办法的更多相关文章
- 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法
本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...
- 浅析:点击父控件时,子控件中的textview自动进入选中状态
原因:父控件属性android:clickable="true",而textview之类的自控件默认不可点击,没有独立的点击监听,这样选中父控件时,textview之类的子控件也进 ...
- bootstrop 日期控件 datepicker被弹出框dialog覆盖的解决办法
筒子们在使用bootstrap的日期控件(datepicker , 现在官网提供的名称叫 datetimepicker)时可能会遇到如上图的问题这是啥原因造成的呢? 答案很简单时输出的优先级造成的(z ...
- phpcmsV9中表单向导在js调用里日期控件在IE下报Calendar未定义的解决办法
最近在phpcmsV9里用表单向导弄个的提交表单,但用了日期和时间类型时,用 <script language='javascript' src='{APP_PATH}index.php?m ...
- 简述Object(ActiveX)控件遮挡Dialog、select下拉框的解决办法
1.背景 最近在做项目的过程中,我们使用了Object控件,但是同时在上面写了一个select下拉框,因此每次点击下拉框的时候我们会发现,下拉框的部分内容被Object控件给遮挡了,调查研究后发现,我 ...
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- 【C#】在窗体中水平居中的控件,到了XP下不居中的解决办法
我时不时会遭遇这个操蛋问题,今天得闲研究了一下,解决如下: A.将窗体FormBorderStyle属性改为Fixed系,当然这会导致用户不能拖拉窗口大小,所以你可能需要B计划↓ B.确保在[VS]中 ...
- MJ刷新控件MJRefreshFooterView上拉之后收不回来的解决办法
修改MJRefreshFooterView.m文件中的这个方法 #pragma mark - 状态相关 #pragma mark 设置状态 - (void)setState:(MJRefreshSta ...
- Nested Loops join时显示no join predicate原因分析以及解决办法
本文出处:http://www.cnblogs.com/wy123/p/6238844.html 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据, ...
随机推荐
- 门外汉的IT
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 计算机很早就走入了我的生活.小学时,家里放一台联想“天琴”的电脑.它霸气的音箱造型 ...
- IDDD 实现领域驱动设计-架构之经典分层
上一篇:<IDDD 实现领域驱动设计-上下文映射图及其相关概念> 在<实现领域驱动设计>书中,分层的概念作者讲述的很少,也就几页的内容,但对于我来说,有很多的感触需要诉说.之前 ...
- spring源码分析之cache demo
spring提供了对echache.guava.jcache的支持,先看一个echache的示例: import org.springframework.cache.CacheManager; imp ...
- 响应式web布局中iframe的自适应
困境 在响应式布局中,我们应该小心对待iframe元素,iframe元素的width和height属性设置了其宽度和高度,但是当包含块的宽度或高度小于iframe的宽度或高度时,会出现iframe元素 ...
- Web接口测试工具---Poster与Postman
工作当中有不少时间在编写和维护接口自动化测试用例.打算先整理一些接口相关工具的使用. 简单对接Web口测试的相关工具/技术做个划分. HTTP/SOAP协议接口的功能测试: 1.浏览器URL(GET请 ...
- Kooboo CMS - Html.FrontHtml[Helper.cs] 各个方法详解
下面罗列了方法详解,每一个方法一篇文章. Kooboo CMS - @Html.FrontHtml().HtmlTitle() 详解 Kooboo CMS - Html.FrontHtml.Posit ...
- Centos6 yum安装openldap+phpldapadmin+TLS+双主配置
原文地址:http://54im.com/openldap/centos-6-yum-install-openldap-phpldapadmin-tls-%E5%8F%8C%E4%B8%BB%E9%8 ...
- 关系数据库常用SQL语句语法大全
创建表 语法 CREATE TABLE <表名>(<列名> <数据类型>[列级完整性约束条件] [,<列名> <数据类型>[列级完整性约束条 ...
- Overload 和Override 的区别
Overload 是重载的意思,Override 是覆盖的意思,也就是重写.重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同).重写 ...
- python 替换 文件夹下的 文件名称 及 文件内容
示例效果: 1.替换某文件夹下的 文件夹及子文件夹 的名称 由OldStrDir 变为 NewStrDir: 2.替换某文件夹下的 文件夹及子文件夹 下 所有的文件的名称 由OldStrFile 变为 ...