You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

滚动ExpandableListView后计数器值错乱问题求助

解决ExpandableListView滚动时数值错乱的问题

我太懂这种滚动后数值乱跳的糟心感了——ExpandableListView的视图复用机制确实很容易给开发者挖坑!核心问题其实很明确:你只更新了UI控件的数值,但没把这些变化同步到数据源里,当视图被复用时,它又会从旧的数据源中读取数据,自然就出现了错乱。下面给你一套实打实的解决方案:

1. 先把数据源结构捋顺

首先要给每个可操作的子项创建一个数据模型类,把需要维护的数值(比如计数)和文本都封装进去,确保每个子项的状态都能被独立存储和修改:

public class ChildItemModel {
    private String itemText;
    private int count;

    // 构造方法、Getter和Setter必须齐全
    public ChildItemModel(String itemText, int initialCount) {
        this.itemText = itemText;
        this.count = initialCount;
    }

    public String getItemText() {
        return itemText;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

你的ExpandableListView数据源要对应层级结构,比如用List<List<ChildItemModel>>来存储分组和子项数据,每个子项都持有自己的count值。

2. 在Adapter中正确绑定数据与UI

重写getChildView方法时,必须遵循先取数据源最新值,再更新UI的逻辑,同时在按钮点击时同步更新数据源:

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    ViewHolder holder;

    // 初始化ViewHolder,复用视图
    if (convertView == null) {
        convertView = LayoutInflater.from(mContext).inflate(R.layout.child_item_layout, parent, false);
        holder = new ViewHolder();
        holder.tvItemText = convertView.findViewById(R.id.tv_item_text);
        holder.tvCount = convertView.findViewById(R.id.tv_count);
        holder.btnAdd = convertView.findViewById(R.id.btn_add);
        holder.btnMinus = convertView.findViewById(R.id.btn_minus);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    // 关键:从数据源获取当前子项的最新数据
    final ChildItemModel currentItem = mChildData.get(groupPosition).get(childPosition);

    // 用数据源的最新值更新UI,覆盖复用视图的旧状态
    holder.tvItemText.setText(currentItem.getItemText());
    holder.tvCount.setText(String.valueOf(currentItem.getCount()));

    // 加号按钮逻辑:先改数据源,再更UI
    holder.btnAdd.setOnClickListener(v -> {
        int newCount = currentItem.getCount() + 1;
        currentItem.setCount(newCount);
        // 精准刷新当前子项,避免全量刷新的卡顿
        notifyChildChanged(groupPosition, childPosition);
        holder.tvCount.setText(String.valueOf(newCount));
    });

    // 减号按钮逻辑:同理,先改数据源
    holder.btnMinus.setOnClickListener(v -> {
        int newCount = currentItem.getCount() - 1;
        if (newCount >= 0) { // 防止出现负数
            currentItem.setCount(newCount);
            notifyChildChanged(groupPosition, childPosition);
            holder.tvCount.setText(String.valueOf(newCount));
        }
    });

    return convertView;
}

// ViewHolder类,用于缓存控件
private static class ViewHolder {
    TextView tvItemText;
    TextView tvCount;
    Button btnAdd;
    Button btnMinus;
}

3. 避坑提醒

  • 绝对不要只修改TextView的文本而不更新数据源:这是最常见的错误,视图复用后旧的UI状态会覆盖新数据。
  • 不要在ViewHolder中存储计数等状态:ViewHolder会被多个子项复用,存储的旧值会导致错乱。
  • 优先用精准刷新方法:notifyChildChanged(groupPosition, childPosition)比notifyDataSetChanged()更流畅,不会导致整个列表重绘。

如果按照上面的步骤操作后还有问题,可以检查下数据源是否在滚动时被意外修改,或者getGroupCount()/getChildCount()方法是否返回了正确的数量。

内容的提问来源于stack exchange,提问作者Anže Mur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:36:47