今天遇到了一个很诡异的问题,Android 的 setEnable(false) 没有作用,网上找的很多方法还是没用。会出现这种情况的有下面几个场景:
- ListView中的子视图setEnable(false)后点击仍然会相应onItemClick
- FrameLayout中上层试图disable后,的确没有响应事件,但是touch事件传递到下层视图了
- ViewGroup调用setEnable(false),不会自动把子视图设为disabled
针对第一个场景,同事给出了一个解决方法:设置一个空的onClickListener
1 2 3 4 5 6 7 |
view.setEnabled ( false ); view.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { // nothing, just to fix the bug that the view can be clicked. } } ); |
其实上面的做法就是消费点击事件但是什么都不做,并不是一般情况下的不消费点击事件。在Android的View源码中我找到了产生这个效果的原因,具体看下面代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public boolean onTouchEvent(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } // ENABLED_MASK为DISABLED时,且isClickable()或isLongClickable()为true时,onTouchEvent 直接return true,消费了事件却不做其他事情 // 而setOnClickListener时,会setClickable(true). ... } /** * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run * * @ see #setClickable(boolean) */ public void setOnClickListener(OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; } |
场景分析
现在再来分析开始提到的三个场景:
- ListView的子试图为disabled后不消费touch事件,接下来传到ListView后调用onItemClick方法,所以子视图自己消费touch事件,就不会传递下去了。
- FrameLayout中的上层视图disabled后,传递到下面的视图跟场景1是一样的,都可以通过前面提过的解决方法解决,不过setOnClickListener可以用setClickable替代。
1 2 |
view.setEnabled(false); view.setClickable(true); |
3. ViewGroup设为disabled之后,子视图仍然可以正常点击,这个问题网上很多人都说用遍历子视图逐个setEnable(false)的方法,不过都是用递归算法实现的,下面我给出循环的实现方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public static void setEnabled(View view, boolean enabled) { if(null == view) { return; } if(view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; LinkedList<ViewGroup> queue = new LinkedList<ViewGroup>(); queue.add(viewGroup); // 遍历viewGroup while(!queue.isEmpty()) { ViewGroup current = queue.removeFirst(); current.setEnabled(enabled); for(int i = 0; i < current.getChildCount(); i ++) { if(current.getChildAt(i) instanceof ViewGroup) { queue.addLast((ViewGroup) current.getChildAt(i)); }else { current.getChildAt(i).setEnabled(enabled); } } } }else { view.setEnabled(enabled); } } |
这篇文章就到这里,有什么问题欢迎大家与我沟通交流。