您的位置:首页 > 其它

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菜鸟,欢迎转载文章,完我的明星梦,打字不易,转载时请注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: