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

嵌套RecyclerView展开异常:滚动时未操作项自动展开问题排查

问题根源与解决方案

这是RecyclerView的ViewHolder复用机制导致的问题:你当前把「展开/收起」的状态直接存在ViewHolder的View控件里,当RecyclerView滚动时,已回收的ViewHolder会被复用给新的列表项,之前的展开状态就会被带到新的item上。而且你没有把展开状态和数据模型绑定,每次绑定ViewHolder时无法恢复对应国家的正确状态。

具体修复步骤

1. 给数据模型添加展开状态字段

修改你的CountryList类,新增一个布尔字段来记录当前国家的展开状态:

public class CountryList {
    // 原有字段
    private String country;
    private List<String> citiesList;
    // 新增展开状态标记
    private boolean isExpanded;

    // 对应的Getter/Setter
    public boolean isExpanded() {
        return isExpanded;
    }

    public void setExpanded(boolean expanded) {
        isExpanded = expanded;
    }

    // 原有构造方法、其他Getter/Setter保持不变
}

2. 修改Adapter的绑定逻辑

在onBindViewHolder中,根据数据模型的isExpanded状态设置城市列表的可见性,同时点击事件要更新数据状态并刷新当前item:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    CountryList countryList = countryArrayList.get(position);
    holder.binding.countryName.setText(countryList.getCountry());

    // 绑定城市列表(这里可以优化,避免每次新建Adapter,后面会说)
    CityRvAdapter cityRvAdapter = new CityRvAdapter(countryList.getCitiesList());
    holder.binding.cityListRv.setAdapter(cityRvAdapter);

    // 关键:根据数据模型的状态设置可见性,而不是依赖ViewHolder缓存的状态
    holder.binding.cityListRv.setVisibility(countryList.isExpanded() ? View.VISIBLE : View.GONE);

    holder.binding.expandCountryButton.setOnClickListener(view -> {
        // 更新数据模型的展开状态
        boolean newState = !countryList.isExpanded();
        countryList.setExpanded(newState);
        // 刷新当前item,确保界面和数据一致
        notifyItemChanged(position);
    });
}

3. (可选)优化Adapter创建性能

每次onBindViewHolder都新建CityRvAdapter会造成不必要的性能损耗,可以把Adapter缓存到ViewHolder中,只更新数据:

  • 先给CityRvAdapter添加更新数据的方法:
public class CityRvAdapter extends RecyclerView.Adapter<CityRvAdapter.ViewHolder> {
    private List<String> cities;

    public CityRvAdapter(List<String> cities) {
        this.cities = cities;
    }

    // 新增更新数据的方法
    public void updateCities(List<String> newCities) {
        this.cities.clear();
        this.cities.addAll(newCities);
        notifyDataSetChanged();
    }

    // 其他原有方法保持不变
}
  • 修改ViewHolder,缓存CityRvAdapter:
public class ViewHolder extends RecyclerView.ViewHolder {
    private CountryBinding binding;
    private CityRvAdapter cityRvAdapter;

    public ViewHolder(CountryBinding binding) {
        super(binding.getRoot());
        this.binding = binding;
        // 初始化一次Adapter,后续只更新数据
        cityRvAdapter = new CityRvAdapter(new ArrayList<>());
        binding.cityListRv.setAdapter(cityRvAdapter);
    }

    // 提供更新城市数据的方法
    public void setCities(List<String> cities) {
        cityRvAdapter.updateCities(cities);
    }
}
  • 最后修改onBindViewHolder:
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    CountryList countryList = countryArrayList.get(position);
    holder.binding.countryName.setText(countryList.getCountry());

    // 只更新城市数据,不新建Adapter
    holder.setCities(countryList.getCitiesList());

    holder.binding.cityListRv.setVisibility(countryList.isExpanded() ? View.VISIBLE : View.GONE);

    holder.binding.expandCountryButton.setOnClickListener(view -> {
        boolean newState = !countryList.isExpanded();
        countryList.setExpanded(newState);
        notifyItemChanged(position);
    });
}

为什么这样修复?

把展开状态和数据模型绑定后,每次ViewHolder被复用时,都会从对应的数据项中读取正确的状态,不会出现「未操作的item自动展开」的问题。点击事件更新数据后调用notifyItemChanged,能确保界面和数据状态完全同步。

内容的提问来源于stack exchange,提问作者eliftekin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 02:06:25