我有一个ExpandableListView风格的购物车。
我正在尝试更新子项目的正确可绘制图形。所有子项目开始显示“+”,我希望在点击时将其更改为“ - ”。
我尝试在适配器中执行此操作但是当我滚动列表并打开其他组标签时,我注意到之前未单击的项目中的项目也被修改。
我不确定我的适配器中的视图回收是否存在问题,或者是否有其他原因造成此问题。这是我的代码:
自定义适配器getChildView方法
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View childView, ViewGroup parent) {
final View row;
final FullMenuItemHolder fullMenuItemHolder;
if (childView == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.full_menu_child_item, parent, false);
fullMenuItemHolder = new FullMenuItemHolder(row);
row.setTag(fullMenuItemHolder);
}
else {
row = childView;
fullMenuItemHolder = (FullMenuItemHolder) row.getTag();
}
// set item name
fullMenuItemHolder.title.setText(getChild(groupPosition, childPosition).getVenue_item_name());
row.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//check to see if item flagged as added to cart and set the respective drawable image
if (!getChild(groupPosition,childPosition).getAddedToCart()) {
getChild(groupPosition,childPosition).setAddedToCart(true);
fullMenuItemHolder.title.setCompoundDrawablesWithIntrinsicBounds(null, null, fragment.getResources().getDrawable(R.drawable.remove), null);
} else {
getChild(groupPosition,childPosition).setAddedToCart(false);
fullMenuItemHolder.title.setCompoundDrawablesWithIntrinsicBounds(null, null, fragment.getResources().getDrawable(R.drawable.add), null);
}
}
});
return row;
}
在片段中设置适配器 (服务器下载后从asyncTask中的onPostExecute调用)
fullMenuExpListAdapter = new FullMenuExpListAdapter(this.getActivity(), listHeaderNames, listChildItems, this);
expandableListView.setAdapter(fullMenuExpListAdapter);
答案 0 :(得分:2)
ListView会重复使用行视图,这就是点击看起来会改变多行的原因。如果你稍微摆动一下这个列表,你还会注意到加号/减号实际上是随机的,之前点击的是哪个都没关系。
在此行之后,您应该手动更新复合drawable,类似于OnClickListener:
// set item name
fullMenuItemHolder.title.setText(getChild(groupPosition, childPosition).getVenue_item_name());
这可确保新行和重用行都显示正确的图标。
(我对您的评论的回复太长了。)
这个问题实际上没有任何随意性,它只是我解释的捷径。 :)
以这种方式思考:在最后一个像素滚出的那一刻,任何完全离开屏幕的行都会被丢弃在回收堆上。它保持原样 - 没有子视图自动清除或修改。
当新行进入屏幕时,ListView首先检查堆剩余物(所需视图类型)。如果找到,您的适配器将有一次机会使用新数据更新所有内容。如果您忘记更新任何内容,您将留下前一项的残余内容 - 例如您原始问题中的可绘制内容。
但请记住,这不仅适用于视觉状态,还适用于行为!
如果您没有创建新的OnClickListener
实例(例如,您将代码放在上面的if
中),groupPosition
和childPosition
将永远不会改变初始值,因此单击一行可能会更新完全不同的模型对象!即使UI看似正确,但模型也会不一致。
将视图更新逻辑从适配器移动到ViewHolder可能很有用,并为它提供一个设置标题,监听器等的bindModel(ChildType child)
方法。它更容易阅读并验证一切都是每次适当设定
(新的RecyclerView工作方式类似,你应该查找它。)
tl; dr:您必须确保在您的适配器实现中更新依赖于行数据模型的所有,否则龙会消耗我们所有人。