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

求助:Android实现固定3行的Horizontal GridView遇BUG无法解决

解决固定3行Horizontal GridView的垂直无限滚动问题

我之前也踩过这个坑!Leanback的HorizontalGridView本来是为电视端场景设计的,放到移动端用确实会出现不少适配问题,尤其是调用setNumRows(int)后出现的垂直无限滚动BUG,真的挺闹心的。结合我自己的开发经验,给你几个亲测有效的解决方案:

方案一:用RecyclerView + GridLayoutManager实现(最推荐)

RecyclerView的灵活性远高于HorizontalGridView,完全可以通过GridLayoutManager轻松实现固定3行的水平滚动网格,而且不会有奇怪的滚动问题。

步骤:

  1. 在布局文件中添加RecyclerView:
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/horizontal_grid_recycler"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
  1. 在代码中配置GridLayoutManager:
// Kotlin示例
val recyclerView = findViewById<RecyclerView>(R.id.horizontal_grid_recycler)
// 第二个参数是列数(这里要实现3行,所以设置spanCount为3,布局方向设为水平)
val gridLayoutManager = GridLayoutManager(this, 3, GridLayoutManager.HORIZONTAL, false)
recyclerView.layoutManager = gridLayoutManager
// 设置适配器(和普通RecyclerView适配器写法完全一致)
recyclerView.adapter = YourCustomGridAdapter()
// Java示例
RecyclerView recyclerView = findViewById(R.id.horizontal_grid_recycler);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3, GridLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(new YourCustomGridAdapter());

这种方式不仅能完美实现固定3行的水平滚动,还能享受RecyclerView的各种特性(比如局部刷新、自定义ItemDecoration等),兼容性也更好,是最省心的选择。

方案二:修复HorizontalGridView的垂直滚动BUG(如果一定要用该组件)

如果你因为某些原因必须使用HorizontalGridView,可以通过重写它的onMeasure方法来限制垂直方向的高度,避免无限滚动:

public class FixedRowsHorizontalGridView extends HorizontalGridView {
    private int mNumRows;

    public FixedRowsHorizontalGridView(Context context) {
        super(context);
    }

    public FixedRowsHorizontalGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FixedRowsHorizontalGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setNumRows(int numRows) {
        super.setNumRows(numRows);
        mNumRows = numRows;
        requestLayout(); // 触发重新测量布局
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 当设置了行数且有子View时,计算总高度并固定
        if (mNumRows > 0 && getChildCount() > 0) {
            int singleRowHeight = getChildAt(0).getMeasuredHeight();
            // 总高度 = 单行高度 × 行数 + 上下内边距
            int totalHeight = singleRowHeight * mNumRows + getPaddingTop() + getPaddingBottom();
            setMeasuredDimension(getMeasuredWidth(), totalHeight);
        }
    }
}

然后在布局中使用你自定义的这个类,调用setNumRows(3)后,组件的垂直高度会被固定为3行的总高度,自然就不会出现无限滚动的问题了。

方案三:用FlexboxLayout替代(备选)

如果你想尝试更灵活的布局,也可以用FlexboxLayout来实现类似效果:

  1. 先添加Flexbox相关依赖
  2. 配置FlexboxLayoutManager:
val flexLayoutManager = FlexboxLayoutManager(this)
flexLayoutManager.flexDirection = FlexDirection.ROW
flexLayoutManager.flexWrap = FlexWrap.NOWRAP
flexLayoutManager.alignItems = AlignItems.STRETCH
// 在适配器中给每个Item设置占比,实现3列布局
// itemView.layoutParams = FlexboxLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
//     flexBasisPercent = 1f / 3
// }

不过这个方案相对GridLayoutManager来说稍显繁琐,还是第一个方案最直接省心。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:12:14