Android Scrollview+Listview 实现不同条目点赞并计数功能及原理分析(2)
来源:互联网 发布:淘宝网买家地域解读 编辑:程序博客网 时间:2024/06/01 09:43
ok,到了第二篇博客,我们继续解决问题。
- 子view中的button等劫持了listview中item的clickListener。
- OnClickListener接口的onClick方法中的View view参数究竟是什么
我们常在listview的item中设置自己喜欢的样式,这其中可能就会出现button和checkBox这样的控件,你可能会遇见item中的button拦截了listview的onItemClickListener,导致其点击事件失效。
这个问题的原因是因为item中的控件霸占了焦点
也许你会把ImageButton改成ImageView然后给它设一个OnClickListener方法,你会发现ImageView并不会强占焦点。很神奇对不对,我们先看这个问题的解决方法,然后回来再说。
网上的解决方法非常多,基本一致:
- 将ListView中的Item布局中的子控件focusable属性设置为false
- 在getView方法中设置button.setFocusable(false)
- 设置item的根布局的属性android:descendantFocusability=”blocksDescendant”
常用的是第三个,从第二个方法中,我们可以感觉出button的focusable属性应该是true,而普通的控件(如TextView)是false的。
看一下源码吧,Button继承TextView,TextView继承View。看一下View对这几个函数的处理。
public void setFocusable(boolean focusable) { if (!focusable) { setFlags(0, FOCUSABLE_IN_TOUCH_MODE); } setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); }
public void setOnClickListener(OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; }
public void setClickable(boolean clickable) { setFlags(clickable ? CLICKABLE : 0, CLICKABLE); }
void setFlags(int flags, int mask) { final boolean accessibilityEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); int old = mViewFlags; mViewFlags = (mViewFlags & ~mask) | (flags & mask); int changed = mViewFlags ^ old; if (changed == 0) { return; } int privateFlags = mPrivateFlags; /* Check if the FOCUSABLE bit has changed */ if (((changed & FOCUSABLE_MASK) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { if (((old & FOCUSABLE_MASK) == FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) != 0)) { /* Give up focus if we are no longer focusable */ clearFocus(); } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) && ((privateFlags & PFLAG_FOCUSED) == 0)) { /* * Tell the view system that we are now available to take focus * if no one else already has it. */ if (mParent != null) mParent.focusableViewAvailable(this); } } final int newVisibility = flags & VISIBILITY_MASK; if (newVisibility == VISIBLE) { if ((changed & VISIBILITY_MASK) != 0) { /* * If this view is becoming visible, invalidate it in case it changed while * it was not visible. Marking it drawn ensures that the invalidation will * go through. */ mPrivateFlags |= PFLAG_DRAWN; invalidate(true); needGlobalAttributesUpdate(true); // a view becoming visible is worth notifying the parent // about in case nothing has focus. even if this specific view // isn't focusable, it may contain something that is, so let // the root view try to give this focus if nothing else does. if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { mParent.focusableViewAvailable(this); } } } /* Check if the GONE bit has changed */ if ((changed & GONE) != 0) { needGlobalAttributesUpdate(false); requestLayout(); if (((mViewFlags & VISIBILITY_MASK) == GONE)) { if (hasFocus()) clearFocus(); clearAccessibilityFocus(); destroyDrawingCache(); if (mParent instanceof View) { // GONE views noop invalidation, so invalidate the parent ((View) mParent).invalidate(true); } // Mark the view drawn to ensure that it gets invalidated properly the next // time it is visible and gets invalidated mPrivateFlags |= PFLAG_DRAWN; } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } } /* Check if the VISIBLE bit has changed */ if ((changed & INVISIBLE) != 0) { needGlobalAttributesUpdate(false); /* * If this view is becoming invisible, set the DRAWN flag so that * the next invalidate() will not be skipped. */ mPrivateFlags |= PFLAG_DRAWN; if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { // root view becoming invisible shouldn't clear focus and accessibility focus if (getRootView() != this) { if (hasFocus()) clearFocus(); clearAccessibilityFocus(); } } if (mAttachInfo != null) { mAttachInfo.mViewVisibilityChanged = true; } } if ((changed & VISIBILITY_MASK) != 0) { // If the view is invisible, cleanup its display list to free up resources if (newVisibility != VISIBLE) { cleanupDraw(); } if (mParent instanceof ViewGroup) { ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), newVisibility); ((View) mParent).invalidate(true); } else if (mParent != null) { mParent.invalidateChild(this, null); } dispatchVisibilityChanged(this, newVisibility); } if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { destroyDrawingCache(); } if ((changed & DRAWING_CACHE_ENABLED) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; invalidateParentCaches(); } if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { destroyDrawingCache(); mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; } if ((changed & DRAW_MASK) != 0) { if ((mViewFlags & WILL_NOT_DRAW) != 0) { if (mBackground != null) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND; } else { mPrivateFlags |= PFLAG_SKIP_DRAW; } } else { mPrivateFlags &= ~PFLAG_SKIP_DRAW; } requestLayout(); invalidate(true); } if ((changed & KEEP_SCREEN_ON) != 0) { if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } } if (accessibilityEnabled) { if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0) { if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } else if ((changed & ENABLED_MASK) != 0) { notifyViewAccessibilityStateChangedIfNeeded( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } } }
可以看到每个控件都可以设置clickable和focusable,这个问题还是很难解释清楚,openStack有这样的解释
Focusable means ACTION_UP event will occur. It will gain it and it won’t release it.
Clickable means ACTION_UP first and ACTION_DOWN at the end. It will gain and release it at the end.
你可以这样理解,focus占用action,所以click不会接收到action,所以被劫持了。
接下来说另外一个问题。
view这个参数可能我们用的不多,其实view就是我们点击的那个图案,比如一个button或者说一个listview中的item。别忘了控件都是继承view的。而且view有一个tag的属性,这个属性可以通过view来传递一些信息,这个属性尤其有用,特别是在listview中。因为我们总是在adapter中设置点击事件,但是可能具体的实现是在外层中,比如activity。这时点击事件就需要传一些相关信息到外层。比如说这个点击事件所属的某个item的position信息。
我们在adapter中传入位置信息
viewHolder.up.setTag(position);
在外层获得
int position = (Integer)view.getTag()
ok,上代码吧,空听我说可能也不明白什么意思。希望能帮你解决问题,下次将继续解决最后的问题。
代码代码
- Android Scrollview+Listview 实现不同条目点赞并计数功能及原理分析(2)
- Android Scrollview+Listview 实现不同条目点赞并计数功能及原理分析(1)
- Android Scrollview+Listview 实现不同条目点赞并计数功能及原理分析(3)
- Android中Listview实现点赞功能
- Android ListView实现不同item的方法和原理分析
- Android ListView实现不同item的方法和原理分析
- android开发游记:ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析
- Android ListView条目全选功能,不用checkbox实现!
- Android ListView条目全选功能,不用checkbox实现!
- Android ListView条目全选功能,不用checkbox实现!
- Android ScrollView中的ListView只显示一个条目问题
- 局部刷新ListView,实现点赞功能
- android listview 加载多种不同视图的条目
- ListView加载不同的条目
- 多条目展示ListView(如:有两种不同的布局图片在listview条目上展示)
- ListView实现类似多米的条目下拉功能
- 对ListView的多条目的一些实现功能
- listview网络请求数据并实现多条目展示
- 【2015/10/25】C 学习日志_Day10 运算符
- 网站外部链接(读书笔记)
- 线段树+离散化操作(poj 2528)
- editplus生成页面框架
- svg动画的学习相关
- Android Scrollview+Listview 实现不同条目点赞并计数功能及原理分析(2)
- 子序列
- Java面试题全集(上)
- C++面试常见题目问与答(汇总一)
- POJ 1204 Word Puzzles // 字典树,枚举, 搜索
- Centos安装gnome主菜单编辑器无
- android中Http类的封装
- 黑马程序员——OC语言日志——内存管理的原理、分类和原则
- eclipse安装ADT