我遇到了这种奇怪的情况,每次我从ListView
的第一个项目中的微调器中选择一个值时,最后一个ListView的
item 其微调器值与第一个项目相同。这种情况仅在 ListView 项目总数5 及以上时发生。我注释掉了代码并只保留了声明,但它仍然在发生。这是 Android 中的错误吗?
澄清:
我的 ListView 的
Scroll Listener
为空我的微调器的
setOnItemSelectedListener
已被注释掉。Android SDK 工具版本为 22.6.2
Android SDK 平台工具为 19.0.1
这是适配器代码:
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
Viewholder v = new Viewholder();
v.rowView = convertView;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (v.rowView == null) {
v.rowView = inflater.inflate(R.layout.inner_base_header_cutom, parent, false);
v.spinner = (Spinner) v.rowView.findViewById(R.id.spinner1);
v.rowView.setTag(v);
} else {
v = (Viewholder) v.rowView.getTag();
}
return v.rowView;
}
ViewHolder:
class Viewholder{
View rowView;
TextView itemPID;
TextView itemPrice;
TextView itemItemId;
Spinner spinner;
TextView subtotal;
}
XML:
<Spinner
android:id="@+id/spinner1"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_margin="20dip"
android:entries="@array/quanitiy"
android:layout_alignTop="@+id/itemPrice"
android:layout_toRightOf="@+id/imageDisplay" />
数组:
<string-array name="quanitiy">
<item>Quantity</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
</string-array>
更新
我注释掉了 OnItemClickListner
的代码。我更新了上面的代码,问题仍然存在。唯一剩下的就是声明。
场景:
如果我在 ListView
的微调器 [index 0] 的第一项选择 1
,则 ListView
的微调器的最后一项也会获得1
无交互。当向下查看 ListView 的项目直到最后一部分时,我发现它们都是相同的。我注释掉了代码,只保留了声明。
最佳答案
好的,现在我明白了。感谢您的澄清。您的问题来自于被回收的 View 。你应该看看this post更好地了解回收。
简短回答
基本上,当您在 getView()
中使用 convertView
时,您正在重用不再可见的项目的 View 。这就是为什么它的字段(包括微调器、价格的 TextView ...)已经设置为某些内容,并且您应该在 getView()
中自行设置它们。这些文本字段和微调器的值应取决于指定位置
处的项目。
详细答案
这是回收的作用(图片取自前面提到的帖子):
你的问题
在这里,当您滚动显示一个新项目(假设为项目 8,如图所示)时,用于显示它的 View 与第一个项目(项目 1)的 View 相同。因此,当您在第一个项目的微调器上选择某些内容,然后向下滚动时,您也会看到最后一个项目的更改,因为您的 getView
不会更改之前的 View 的值。用于第 1 项(但应该更新它们!)。
注意:您的案例中第一项和最后一项的对应关系完全是偶然的。通常,该 View 会重复用于 2 个项目,这两个项目的间隔大约等于一个屏幕高度中的项目数量,如图所示。
您的代码中的 getView
内联解释
Viewholder v = new Viewholder(); // why create a new one, while you might reuse the former one?
// here rowView becomes the same as the former item's view, with all the former values
v.rowView = convertView;
// you don't need this here but only in the case rowView is null, should be in your 'if'
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (v.rowView == null) {
v.rowView = inflater.inflate(R.layout.inner_base_header_cutom, parent,false);
v.spinner = (Spinner) v.rowView.findViewById(R.id.spinner1);
v.rowView.setTag(v);
// here you inflated a new view (nothing reused)
// but you didn't initialize anything
} else {
v = (Viewholder) v.rowView.getTag();
// here you're reusing the former View and ViewHolder
// and you don't change the values
}
解决方案
您不应该让项目按照自己的意愿行事,但您应该告诉它们在 getView()
中初始化项目 View 的内容时要显示什么。对于上图,这意味着您需要将原来的第 1 项更改为第 8 项。
您应该在适配器中保留每个项目的状态。您可能有一个后备列表或其他东西来根据位置
在ListView
中显示不同的元素,对吧?
然后,您应该使用类似的列表(或相同的列表)来存储在微调器中选择的值、价格文本字段显示的值等。无论如何,这些可能应该与当前列表中的项目字段相对应,因此您可能已经有地方可以存放它们了。
另一方面,当您在 getView()
中重用 convertView
时,请确保使用以下命令初始化微调器(和文本字段以及此项目 View 中的所有内容) 位置
处的项目的正确值。
getView
的解决方案代码(模板)
Viewholder v;
if (convertView == null) {
// create a new holder for the new item view
v = new Viewholder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v.rowView = inflater.inflate(R.layout.inner_base_header_cutom, parent,false);
v.rowView.setTag(v);
// populate the new holder's fields
v.spinner = (Spinner) v.rowView.findViewById(R.id.spinner1);
v.itemPID = (TextView) v.rowView.findViewById(...); // put the right ID here
v.itemPrice = (TextView) v.rowView.findViewById(...); // put the right ID here
v.itemItemId = (TextView) v.rowView.findViewById(...); // put the right ID here
v.subtotal = (TextView) v.rowView.findViewById(...); // put the right ID here
} else {
v = (Viewholder) convertView.getTag();
// the views of v are already populated here (reused)
}
/*
* Reused or not, the item view needs to be initialized here.
* Initialize all views contained in v with values that are
* meaningful for the item at 'position'.
*/
// for instance:
MyItemClass theItemAtPosition = myBackingList.get(position);
v.subtotal.setText(String.valueOf(theItemAtPosition.getSubtotal()));
v.spinner.setSelection(theItemAtPosition.getQuantity());
// to be continued, you get the idea ;)
关于java - 内部带有微调器的 ListView : 1st Item of the listview affects its last item,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22809526/