点击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 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据, ...
随机推荐
- 编译器出现conflicting types for 某某的错误原因总结
直译就是xxxx 发生了一种冲突!比如今天发现的这个错误,实属低级! 本次错误的原因是:函数没有先声明,便写在了主函数后面!应该是先声明,后定义,如果只有定义,则定义必须写在主函数上方.通过查资料,有 ...
- struts2学习笔记--动手搭建环境+第一个helloworld项目
在Myeclipse中已经内置好了struts2的环境,但是为了更好的理解,这里自己从头搭建一下: 前期准备:下载struts2的完整包,下载地址:https://struts.apache.org/ ...
- (1)从底层设计,探讨插件式GIS框架的实现
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 研一时,听当时的师兄推荐,买了蒋波涛的一本关于GIS插件框架的书.当时 ...
- 4.Java网络编程之TCP/UDP
常见传输协议: UDP , TCP UDP协议: 特点: 1.将数据及源和目的封装成数据包中,不需要建立连接 2.每个数据包的大小限制在64K内 ...
- Linux下使用FreeTDS访问MS SQL Server 2005数据库(包含C测试源码)
Linux下使用FreeTDS访问MS SQL Server 2005数据库(包含C测试源码) http://blog.csdn.net/helonsy/article/details/7207497 ...
- Mybatis XML 映射配置文件 -- 熟悉配置
来源:http://www.mybatis.org/mybatis-3/zh/configuration.html properties mybatis读取属性顺序. 如果属性在不只一个地方进行了配置 ...
- Struts2 源码分析——调结者(Dispatcher)之action请求
章节简言 上一章笔者讲到关于struts2启动的时候加载对应的准备工作.如加载配置文件struts.xml之类的信息.而相应的这些操作都离不开Dispatcher类的帮助.如果读者只是认为Dispat ...
- iOS的一些面试题分析总结(1)
本篇主要说一下多线程的东西,因为东西比较多,所以直接拿出一整个篇幅来说它了. 3. 多线程的底层实现? 1.先说一下什么是进程,什么是线程.什么是多线程. 进程是资源分配的单位,线程是调度运行的基本单 ...
- 7.5 数据注解特性--MaxLength&&MinLength
MaxLength attribute can be applied to a string or array type property of a domain class. EF Code Fir ...
- sqlHelper做增删改查,SQL注入处理,存储值,cookie,session
一.存储值 eg:登录一个页面,在进入这个页面之前你怎么知道它登没登录呢?[在登录成功之后我们把状态保存起来] 存储值得方式有两种,一种是cookie,一种是session 1.1区别: 代码: if ...