我遇到了类似的问题,我花了 2 天时间来调试并解决它。
我有一个 ListAdapter,它在 LinearLayout 中为每个列表项创建几个 TextView。
每个 TextView 都有自己的 OnClickListener,因为我需要处理每个项目的点击。
当我更改实现以便重用视图时,OnClickListener 停止正常工作。在 4.4.2 上,大多数点击都有效,但有时在我滚动列表之前没有任何反应。在 2.3 上,第一次点击无法正常工作,然后所有点击都会突然处理。
在我的特殊情况下,我在 Java 代码中创建了所有视图,而不是通过膨胀资源。
关键点是,即使视图被重用,我也确实设置了 LinearLayout 的 LayoutParams(这似乎更安全,然后假设重用的视图具有正确的布局参数)。
当我在重用时不设置 LayoutParams 一切正常!
这是关键代码:
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout tapeLine = null;
if (convertView != null && convertView instanceof LinearLayout && ((LinearLayout)convertView).getChildCount() == 4) tapeLine = (LinearLayout) convertView; // Reuse view
else tapeLine = new LinearLayout(activity);
if (convertView == null) { // Don't set LayoutParams when reusing view
ViewGroup.LayoutParams tapeLineLayoutParams = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tapeLine.setLayoutParams(tapeLineLayoutParams);
}
ScrollingTape scrollingTape = calculatorHolder.getCalculator().getScrollingTape();
int tapeWidthPx = parent.getWidth();
TapeLineTextSizeInfo tapeLineTextSizeInfo = calculatorHolder.getTapeLineTextSizeHelper().createTapeLineTextSizeInfo(tapeWidthPx);
ScrollingTapeLine line = scrollingTape.getLine(position);
tapeLine.setOrientation(LinearLayout.HORIZONTAL);
int tapeBackgroundColor = getBackgroundColor(line);
tapeLine.setBackgroundColor(tapeBackgroundColor);
addColumnViews(tapeLine, line, tapeLineTextSizeInfo);
tapeLine.setTag(R.id.scrollingtapeadapter_viewtag_position, position);
tapeLine.setOnLongClickListener(longClickListener);
tapeLine.setOnClickListener(remainClickListener);
return tapeLine;
}
列表视图这种奇怪行为的背景是什么?
我在 Android 源代码中做了一些调试和研究。
当 android 更新一个视图时,有两个重要的步骤 onMeasure 和 onLayout。
ListAdapter 的 getView 方法不仅被调用来绘制视图,而且在 onMeasure 期间也更早地被调用。在后一种情况下,视图已创建,但尚未在事件链中注册以处理点击事件。
当一个为onMeasure创建的视图在以后被重用以精确地绘制到屏幕上时,它必须从Android系统中注册来处理点击事件。
对于这种特殊情况,Android 开发人员做了一些事情,这可以被认为是一个肮脏的 hack。 LayoutParams 中的一个特殊标志用于决定必须在事件更改中注册视图。
现在我的问题是:通过在重用视图时也重置 LayoutParams,这个标志总是被重置。因此Android系统不会注册视图,事件也不会通过。
总结一下:在 ListAdapter 的 getView 中重用视图时,不要覆盖 LayoutParams,因为它们保留了 android 系统的内部信息。