ExpandableListView点击最后一个child item不回调onChildClick()的问题
2016-03-10 17:06
477 查看
遇到的问题:
在使用ExpandableListView及其子类控件时,如果你通过调用setOnChildClickListener(OnChildClickListener onChildClickListener)方法去设置监听器去监听child item的点击事件,会发现在Android 4.3(包括4.3)以下的系统的手机上,这个监听器无法监听到最后一个child item的点击事件。
问题根源:
遇到这个问题的时候,最初始的猜想是ExapandableListView在回调OnChildClickListener的onChildClick()方法之前把最后一个child item的点击事件给截住了。但到底为什么会被截住了,那肯定是要去看源码了。然后发现是在ExapandableListView类中的handleItemClick()方法中回调onChildClick()方法:
/** * This will either expand/collapse groups (if a group was clicked) or pass * on the click to the proper child (if a child was clicked) * * @param position The flat list position. This has already been factored to * remove the header/footer. * @param id The ListAdapter ID, not the group or child ID. */ boolean handleItemClick(View v, int position, long id) { final PositionMetadata posMetadata = mConnector.getUnflattenedPos(position); id = getChildOrGroupId(posMetadata.position); boolean returnValue; if (posMetadata.position.type == ExpandableListPosition.GROUP) { /* It's a group, so handle collapsing/expanding */ /* It's a group click, so pass on event */ ...... ...... returnValue = true; } else { /* It's a child, so pass on event */ if (mOnChildClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); return mOnChildClickListener.onChildClick(this, v, posMetadata.position.groupPos, posMetadata.position.childPos, id); } returnValue = false; } posMetadata.recycle(); return returnValue; }
这个方法里面看不出什么毛病,都是根据被点击的item的position判断这个item是group item还是child item,再调用对应的回调方法。那既然这里看不出什么毛病,就再去看看调用这个handleItemClick()的地方看看。搜索handleItemClick,发现这个方法是在performItemClick()方法中被调用:
@Override public boolean performItemClick(View v, int position, long id) { // Ignore clicks in header/footers if (isHeaderOrFooterPosition(position)) { // Clicked on a header/footer, so ignore pass it on to super return super.performItemClick(v, position, id); } // Internally handle the item click final int adjustedPosition = getFlatPositionForConnector(position); return handleItemClick(v, adjustedPosition, id); }
咦,这里可以看出一些端倪了,这里在调用handleItemClick()方法之前,会根据被点击的item的position判断这个item是否Header或者Footer,如果是,就不会调用handleItemClick()方法,那也自然不会回调OnChildClickListener的onChildClick()方法。那究竟问题是不是出现在这里呢,让我们继续跟进去判断是否Header或者Footer的方法isHeaderOrFooterPosition()中看看是怎么判断的:
/** * @param position An absolute (including header and footer) flat list position. * @return true if the position corresponds to a header or a footer item. */ private boolean isHeaderOrFooterPosition(int position) { // 这里先算出FooterView的开始位置,注意这里的mItemCount变量是在其父类ListView中定义的 // 而mItemCount的值其实就等于mAdapter.getCount() final int footerViewsStart = mItemCount - getFooterViewsCount(); // 这里就开始判断这个position是否Header或者Footer return (position < getHeaderViewsCount() || position >= footerViewsStart); }
那既然现在是最后一个child item出现问题,那此时可以大胆猜测问题可能出在这个footerViewsStart上,那想要证实我们的猜测,那就把这个变量打印出来看看就好了。想要打印这个变量,我的方法是写一个类继承ExpandableListView,然后重写performItemClick(),在该方法中模仿isHeaderOrFooterPosition()方法中的footerViewsStart的计算方式,模拟出footerViewsStart的值,然后打印到logcat上:
public class TestExpandableListView extends ExpandableListView { private final static String TAG = "TestExpandableListView"; public TestExpandableListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean performItemClick(View v, int position, long id) { Log.d(TAG, "getAdapter().getCount() = " + getAdapter().getCount()); Log.d(TAG, "getFooterViewsCount() = " + getFooterViewsCount()); return super.performItemClick(v, position, id); } }
通过查看logcat发现,如果ExpandableListView有FooterView的话(即getFooterViewsCount()返回的值大于0),在Android 4.3(包括4.3)以下的系统的getAdapter().getCount()返回的值是没有把FooterView的数量给加上,而Android 4.3以上的则会加上。这就直接导致了在有FooterView的情况下,Android 4.3(包括4.3)以下的系统把最后一个child item当成是FooterView导致没有回调OnChildClickListener的onChildClick()方法的问题了。
到这里问题根源终于找到了,google也是发现了这个bug了,所以在Android 4.4.4版本就已经把这个问题给修复了。
如何解决
问题找到了,那接下来该如何去解决呢?我的解决方法其实是很粗暴,但也很简单,就是放弃使用OnChildClickListener监听器,而在Adapter中通过设置child item的convertView的onClik事件来监听每个child item的点击。
如果大家有什么更好的方法欢迎各位热烈评论交流。
多谢各位客官花时间帮衬本文章,本yeah目前是Android菜鸟,欢迎转载文章,完我的明星梦,打字不易,转载时请注明出处。
相关文章推荐
- 我的二次创业——Egret Html5游戏引擎
- machine learning:计算error时lambda取值
- ubuntu之组和用户名
- 字符串交错组成--很优美的递归算法
- Spring MVC学习笔记 01
- Linux进程间通信——使用消息队列
- Hadoop系列二:Hadoop单节点伪分布部署并执行mapreduce示例wordcount
- 很特别的一个动态规划入门教程
- 20160310第二题
- ORA-12514 TNS:listener does not currently know of service requested in connect descriptor
- autocomplete+PHP+MYSQL的实现模糊查询
- .net 伪静态、真静态 (mvc)
- NPM是什么
- 很特别的一个动态规划入门教程
- 很特别的一个动态规划入门教程
- 很特别的一个动态规划入门教程
- 很特别的一个动态规划入门教程
- apple remote desktop
- Go项目的目录结构
- python代码格式检查工具部署pre_commit