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

使用GridLayoutManager的RecyclerView首次加载Cell高度异常问题

问题分析与解决方案

这种首次加载布局异常、切换Tab后恢复的情况,核心原因通常是首次布局时RecyclerView或Cell的尺寸还未正确计算,再加上Picasso异步加载图片的特性,导致LinearLayout的weight布局计算出现偏差。咱们一步步来解决:

核心问题拆解

  1. RecyclerView尺寸未就绪:你的RecyclerView用了0dp(match_constraint)依赖ConstraintLayout约束,首次初始化时它的宽度还没完成测量,此时你尝试计算的item宽度是不准确的。
  2. 图片异步加载影响布局:Picasso加载图片是异步的,首次加载时ImageView显示的是占位图@drawable/icon,它的尺寸和服务器返回的实际图片可能不一致,导致LinearLayout基于weight分配的高度不符合预期。切换Tab后图片已缓存,ImageView有了正确尺寸,布局自然恢复正常。

具体修复步骤

1. 等RecyclerView布局完成后再初始化Adapter

在Fragment的onViewCreated方法中,监听RecyclerView的全局布局事件,确保它的尺寸确定后再计算item宽度并设置Adapter:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    RecyclerView recyclerView = view.findViewById(R.id.recyclerViewCategories);
    recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));

    // 监听RecyclerView布局完成事件
    recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // 移除监听,避免重复触发
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
                recyclerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }

            // 计算item宽度:RecyclerView宽度的1/2,减去左右margin(你的Cell有10dp的margin)
            int recyclerViewWidth = recyclerView.getWidth();
            int itemWidth = (recyclerViewWidth - 2 * getResources().getDimensionPixelSize(R.dimen.cell_margin)) / 2;
            // 这里建议把10dp定义成dimen资源,方便统一修改

            // 初始化Adapter并设置
            List<MedicineCategoryDataModel> categoryData = ...; // 你的数据
            CategoryRecyclerViewAdapter adapter = new CategoryRecyclerViewAdapter(getContext(), categoryData, itemWidth);
            recyclerView.setAdapter(adapter);
        }
    });
}

2. 在Adapter中正确设置Cell尺寸并监听图片加载完成

修改Adapter的代码,在onBindViewHolder中设置Cell的宽高,并在图片加载完成后刷新当前item,确保布局重新计算:

public class CategoryRecyclerViewAdapter extends RecyclerView.Adapter<CategoryRecyclerViewAdapter.ViewHolder> {
    // ... 其他成员变量
    private int itemWidth;

    public CategoryRecyclerViewAdapter(Context context, List<MedicineCategoryDataModel> data, int width) {
        this.layoutInflater = LayoutInflater.from(context);
        this.categoryData = data;
        this.context = context;
        this.itemWidth = width; // 接收计算好的item宽度
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        MedicineCategoryDataModel item = categoryData.get(position);
        holder.textViewCategoryName.setText(item.categoryName);

        // 设置Cell的宽高(因为要正方形,高度等于宽度)
        ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
        params.width = itemWidth;
        params.height = itemWidth;
        holder.itemView.setLayoutParams(params);

        // 加载图片并监听完成事件
        String iconUrl = item.iconUrl;
        EPClientLayer.getInstance().getImageHandler().loadImage(context, iconUrl, holder.imageViewCategoryIcon, new Callback() {
            @Override
            public void onSuccess() {
                // 图片加载完成后,通知RecyclerView刷新当前item,让布局重新计算
                notifyItemChanged(position);
            }

            @Override
            public void onError() {
                // 可选:处理图片加载失败的情况
            }
        });
    }

    // ... 其他代码
}

3. 优化Cell布局的小细节

  • 把TextView的textSize="15dp"改成15sp,sp是专门用于文字大小的单位,适配不同系统字体大小设置。
  • 给ImageView添加android:scaleType="centerCrop",避免图片拉伸变形,保证显示效果一致:
<ImageView
    android:id="@+id/categoryImage"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginLeft="40dp"
    android:layout_marginRight="40dp"
    android:layout_weight="0.8"
    android:scaleType="centerCrop"
    android:src="@drawable/icon" />

为什么之前的方法无效?

你之前尝试在onCreateViewHolder中设置尺寸,此时RecyclerView的parent布局还未完成测量,获取到的宽度是不准确的;直接用屏幕宽度计算没有考虑RecyclerView的margin和约束布局的影响,同样会导致尺寸偏差。只有等RecyclerView完全布局完成后,获取的宽度才是真实可用的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:08:25