更新 ExpandableListView 中的子项

Updating child item in ExpandableListView

我有一个 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);

行视图正在被 ListView 重复使用,这就是点击似乎更改了多行的原因。如果您稍微调整一下列表,您还会注意到 plus/minus 标志实际上是随机的,之前点击过哪些并不重要。

在此行之后,您应该手动更新复合可绘制对象,类似于您的 OnClickListener:

// set item name
fullMenuItemHolder.title.setText(getChild(groupPosition, childPosition).getVenue_item_name());

这可确保新行和重复使用的行都显示正确的图标。


(我对你评论的回复太长了。)

这个问题其实没有什么随机的,只是帮我解释的一个捷径。 :)

这样想:任何完全离开屏幕的行都会在最后一个像素滚出时被扔到回收堆上。它保持原样 - 没有子视图被自动清除或修改。

当新行进入屏幕时,ListView 首先检查堆中是否有剩余(所需视图类型)。如果找到,您的适配器将有一次机会用新数据更新所有内容。如果您忘记更新任何内容,您将留下早期项目的残余 - 就像您原始问题中的可绘制对象。

但请记住,这不仅适用于视觉状态,还适用于行为

如果您没有创建新的 OnClickListener 实例(例如,您将代码放在上面的 if 中),groupPositionchildPosition 将永远不会改变从初始值开始,因此单击一行可能会更新一个完全不同的模型 object!尽管 UI 看似正确,但模型会不一致。

将视图更新逻辑从 Adapter 移动到您的 ViewHolder 并为其提供一个设置标题、侦听器等的单一 bindModel(ChildType child) 方法可能会很有用。这样更容易阅读和验证每次都设置得当。
(新的 RecyclerView 的工作原理类似,你应该看看。)


tl;dr:必须确保在您的适配器实现中更新所有内容这取决于行的数据模型,否则龙会吞噬我们所有人。