求助:Android实现固定3行的Horizontal GridView遇BUG无法解决
解决固定3行Horizontal GridView的垂直无限滚动问题
我之前也踩过这个坑!Leanback的HorizontalGridView本来是为电视端场景设计的,放到移动端用确实会出现不少适配问题,尤其是调用setNumRows(int)后出现的垂直无限滚动BUG,真的挺闹心的。结合我自己的开发经验,给你几个亲测有效的解决方案:
方案一:用RecyclerView + GridLayoutManager实现(最推荐)
RecyclerView的灵活性远高于HorizontalGridView,完全可以通过GridLayoutManager轻松实现固定3行的水平滚动网格,而且不会有奇怪的滚动问题。
步骤:
- 在布局文件中添加RecyclerView:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/horizontal_grid_recycler" android:layout_width="match_parent" android:layout_height="wrap_content"/>
- 在代码中配置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来实现类似效果:
- 先添加Flexbox相关依赖
- 配置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
相关产品推荐
相关产品推荐

