android中点击viewgroup时,子控件也会变成被点击的状态的原因及解决方法

发布时间:2016-12-11 2:30:34 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"android中点击viewgroup时,子控件也会变成被点击的状态的原因及解决方法",主要涉及到android中点击viewgroup时,子控件也会变成被点击的状态的原因及解决方法方面的内容,对于android中点击viewgroup时,子控件也会变成被点击的状态的原因及解决方法感兴趣的同学可以参考一下。

前不久在做一个社交应用时,遇到了这样一个问题:点击listview的item时,里面若含有子控件(button或者image等等)且设置了selector,则也会变成被点击的状态。而此时,其实是没有点中这些控件的。这些控件的onClick回调并不会被执行,只是外观发生了变化。 在解决问题之前,我们先来说说的stateListDrawable。 stateListDrawable是用xml定义的用用多张图片去表示某一个图像的drawable对象,它在不同的状态下会显示不同的图片。这取决于你在xml中的设置。 下面是官网上列出来的状态类型: ?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"     android:constantSize=["true" | "false"]     android:dither=["true" | "false"]     android:variablePadding=["true" | "false"] >     <item         android:drawable="@[package:]drawable/drawable_resource"         android:state_pressed=["true" | "false"]         android:state_focused=["true" | "false"]         android:state_hovered=["true" | "false"]         android:state_selected=["true" | "false"]         android:state_checkable=["true" | "false"]         android:state_checked=["true" | "false"]         android:state_enabled=["true" | "false"]         android:state_activated=["true" | "false"]         android:state_window_focused=["true" | "false"] /> </selector> 看到这里,我们发现了一个表象上的原因,那就是当我们点击viewgroup时,里面的控件的状态也被修改为pressed了。也就是说,viewgrouop把pressed状态传递到了它的子控件中。为了解决这个问题,我们得去看看pressed状态是如何传递的。 当一个view被按下时,setPressed(boolean pressed)会被调用,用来设置该view被点击的的状态。当pressed为true时,view的状态为pressed。也即会显示被点击时的图片。下面是sdk2.1(我使用的是2.1)中setPressed函数的代码: public void setPressed(boolean pressed) { if (pressed) { mPrivateFlags |= PRESSED; } else { mPrivateFlags &= ~PRESSED; } refreshDrawableState(); dispatchSetPressed(pressed); } 最后的dispatchSetPressed(pressed)函数负责的就是把pressed状态传递给子控件。 所以,我们再来看看ViewGroup对dispatchSetPressed的重写: @Override protected void dispatchSetPressed(boolean pressed) { final View[] children = mChildren; final int count = mChildrenCount; for (int i = 0; i < count; i++) { children[i].setPressed(pressed); } } 惊讶地发现ViewGroup竟然没有任何判断和约束地遍历了一遍子view,将自己的pressed状态传到每一个子View去了。我觉得这算是SDK2.1设计上的一个缺漏吧。 再来看看SDK4.1的代码: @Override protected void dispatchSetPressed(boolean pressed) { 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())) { child.setPressed(pressed); } } } 果然,在后面的版本中对这部分作了改进,加了一层判断,当子View自身可以被点击时,pressed状态不会被传递过去。 看到这里,相信大家都知道如何去解决了。那就是创建一个新的类,继承ViewGroup(或者LinearGroup,RelativeGroup等ViewGroup的子类),重写dispatchSetPressed函数,改写为4.1版本的代码。用它来替代原来的ViewGroup,然后将其子控件的clickable设成true即可。 下面是我重写的代码: public class UnpressedLayout extends RelativeLayout{ private boolean pressEnable = true; public unpressedLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override protected void dispatchSetPressed(boolean pressed) {         final int count = getChildCount();         for (int i = 0; i < count; i++) {             final View child = getChildAt(i);             if (!pressed || (!child.isClickable() && !child.isLongClickable())) {                 child.setPressed(pressed);             }         }     } }

上一篇:windows消息和消息队列
下一篇:Android UDP组播示例源代码

相关文章

相关评论