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

Android RecyclerView GridLayout中setText与onClick功能异常求助

RecyclerView GridLayout 点击单个Item导致多个Item异常变化的解决方案

问题根源

核心原因是RecyclerView的ViewHolder复用机制:你直接修改View的高度和文本,但未将这些状态持久化到数据源中。当RecyclerView滚动时,被回收的ViewHolder会被复用给其他位置的Item,导致这些被复用的Item继承了之前修改的属性,出现多个Item同时变化的问题。添加FrameLayout后文本问题解决,但高度问题依然存在,是因为高度修改还是直接作用在View上,没有和数据源绑定,复用后依然会影响其他Item。

解决方案

步骤1:创建数据类存储Item状态

创建ItemData类,保存每个Item的独立状态,确保状态可追踪、可复用:

public class ItemData {
    private int originalHeight;
    private int currentHeight;
    private String text;

    public ItemData(int originalHeight, String text) {
        this.originalHeight = originalHeight;
        this.currentHeight = originalHeight;
        this.text = text;
    }

    public int getCurrentHeight() { return currentHeight; }
    public void setCurrentHeight(int currentHeight) { this.currentHeight = currentHeight; }
    public String getText() { return text; }
    public void setText(String text) { this.text = text; }
}

步骤2:修改Adapter绑定数据源状态

重构CustomAdapter,用数据源管理每个Item的状态,点击事件中更新数据源并局部刷新:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private List<ItemData> itemList;
    private final int additionalHeight = 50;

    public CustomAdapter(List<ItemData> itemList) {
        this.itemList = itemList;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textViewContainingImageOnTop;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            textViewContainingImageOnTop = itemView.findViewById(R.id.top_image_bottom_text_card);
        }
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View cardItem = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_item, parent, false);
        return new ViewHolder(cardItem);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        ItemData data = itemList.get(position);
        // 根据数据源设置文本
        holder.textViewContainingImageOnTop.setText(data.getText());
        // 根据数据源设置高度
        ViewGroup.LayoutParams params = holder.textViewContainingImageOnTop.getLayoutParams();
        params.height = data.getCurrentHeight();
        holder.textViewContainingImageOnTop.setLayoutParams(params);

        // 点击事件:更新数据源+局部刷新
        holder.textViewContainingImageOnTop.setOnClickListener(v -> {
            // 更新高度
            data.setCurrentHeight(data.getCurrentHeight() + additionalHeight);
            // 可选:更新文本
            data.setText("Clicked: " + position);
            // 仅刷新当前Item,避免全局刷新
            notifyItemChanged(position);
        });
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }
}

步骤3:修改Fragment初始化数据源

在TestFragment中初始化每个Item的初始状态,将dp转换为像素值确保跨设备一致性:

public class TestFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_calendar, container, false);

        RecyclerView mRecyclerView = rootView.findViewById(R.id.recycler_view);
        // 初始化数据源
        List<ItemData> itemList = new ArrayList<>();
        int originalHeightDp = 200;
        int originalHeightPx = dpToPx(getActivity(), originalHeightDp);
        for (int i = 0; i < 20; i++) {
            itemList.add(new ItemData(originalHeightPx, "position: " + i));
        }
        CustomAdapter mCustomAdapter = new CustomAdapter(itemList);
        mRecyclerView.setAdapter(mCustomAdapter);

        GridLayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 2);
        mRecyclerView.setLayoutManager(mLayoutManager);

        return rootView;
    }

    // dp转px工具方法
    private int dpToPx(Context context, int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
    }
}

步骤4:保持布局正确

沿用你UPDATE后的card_item.xml,根布局FrameLayout设为wrap_content,让RecyclerView自动适配Item高度:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/top_image_bottom_text_card"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:drawableTopCompat="@drawable/cherry_tomatoes_card_icon" />
</FrameLayout>

关键说明

  • 状态持久化:所有Item的高度、文本状态都绑定到数据源,ViewHolder复用时会重新读取状态,彻底解决复用异常。
  • 局部刷新:使用notifyItemChanged(position)替代全局刷新,提升性能同时避免不必要的UI重绘。
  • 单位转换:将dp转为像素值,保证不同分辨率设备上的高度显示一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:16:05