8、横向滚动列表:设置 LinearLayoutManager 为 HORIZONTAL

说实话,很多新手做列表时,脑子里默认就是上下滑。但实际项目中,横向滚动的需求太常见了——图片轮播、标签选择、商品推荐卡片……你想想看,几乎每个App里都有那么一两个横向滑动的区域。

这一章我们就专门聊聊,怎么把 RecyclerView 从「竖着滑」变成「横着滑」。其实改动非常小,但背后有些细节值得注意。

核心改动:一行代码的事

要让 RecyclerView 横向滚动,关键就在 LinearLayoutManager 的构造参数上。默认情况下,我们用的是:

val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager

这样得到的是垂直滚动。改成横向只需要加一个参数:

val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.layoutManager = layoutManager

第二个参数传 HORIZONTAL,第三个参数是 reverseLayout,一般传 false 表示从左到右排列。如果你传 true,那就会从右向左滚动——嗯,某些阿拉伯语系的App可能会用到。

关键点:LinearLayoutManager 的构造方法有三个参数:

  • context:上下文
  • orientation:方向,VERTICAL 或 HORIZONTAL
  • reverseLayout:是否反向布局

布局上的调整

方向变了,item 的布局也得跟着调整。我个人习惯把 item 的宽度设为 wrap_content 或者一个固定值,高度设为 match_parent。为什么呢?因为横向滚动时,每个 item 的高度通常由 RecyclerView 的高度决定,而宽度则需要我们显式控制。

举个例子,一个横向的图片列表:

<!-- item_image.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="120dp"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="4dp">

    <ImageView
        android:id="@+id/iv_thumb"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/tv_label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="12sp" />
</LinearLayout>

这里宽度设了 120dp,高度撑满父布局。如果你设成 match_parent,那每个 item 就会占满整个屏幕宽度——横向滚动就变成了一屏一屏翻页的效果,这可能是你想要的,也可能不是。

小技巧:如果你希望 item 宽度自适应内容,可以用 wrap_content。但要注意,RecyclerView 的父布局宽度要设成 match_parent,否则可能撑不开。

我在项目中踩过的坑

我曾经在一个电商项目里做横向推荐列表,遇到一个奇怪的问题:列表滑到最右边时,最后一个 item 只显示了一半。排查了半天,发现是 RecyclerView 的父布局用了 wrap_content,导致 RecyclerView 自身宽度不够。

解决方案很简单:把 RecyclerView 的宽度设为 match_parent,或者给父布局一个固定宽度。另外,如果你用 ConstraintLayout,记得给 RecyclerView 加上左右约束。

避坑指南:横向 RecyclerView 嵌套在 ScrollView 或 NestedScrollView 里时,会出现滑动冲突。我曾经被这个问题折磨了一下午——横向滑动总是被父布局拦截。解决方案是给 RecyclerView 重写 onInterceptTouchEvent,或者用 NestedScrollView 配合 setNestedScrollingEnabled(false)

完整示例代码

下面是一个完整的横向列表实现,包含 Adapter 和 Activity 的代码:

// HorizontalAdapter.kt
class HorizontalAdapter(private val items: List<String>) :
    RecyclerView.Adapter<HorizontalAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_horizontal, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(items[position])
    }

    override fun getItemCount() = items.size

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val tvLabel: TextView = itemView.findViewById(R.id.tv_label)

        fun bind(text: String) {
            tvLabel.text = text
        }
    }
}

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
        val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        recyclerView.layoutManager = layoutManager

        val data = listOf("推荐1", "推荐2", "推荐3", "推荐4", "推荐5")
        val adapter = HorizontalAdapter(data)
        recyclerView.adapter = adapter
    }
}

横向列表的常见应用场景

场景 说明 Item 宽度建议
图片轮播 全屏宽度,左右滑动切换 match_parent
标签选择 横向排列的标签,可多选 wrap_content
商品推荐 一行显示多个商品卡片 固定值(如 150dp)
分类导航 类似 Tab 的横向导航 wrap_content 或固定值

SVG 结构图:横向列表的核心逻辑

横向滚动列表核心逻辑 LinearLayoutManager orientation = HORIZONTAL Item 布局:宽度固定 / wrap_content 水平滑动 注意:父布局宽度需 match_parent,避免 item 显示不全

总结

横向滚动列表,说白了就是改一个参数的事。但真正用好它,你需要关注三点:

  • 方向参数LinearLayoutManager.HORIZONTAL
  • Item 宽度:根据场景选择固定值或 wrap_content
  • 父布局宽度:确保 RecyclerView 有足够的空间

嗯,这一章的内容其实不多,但横向列表在实际项目中出现的频率非常高。下一章我们会聊聊更进阶的话题——如何给列表添加分割线,让 UI 更精致。