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

垂直RecyclerView嵌套水平RecyclerView:点击时如何获取垂直项位置?

这个问题我在做类似Google Play的嵌套RecyclerView布局时也踩过坑!其实核心就是要把垂直RecyclerView的当前item位置传递给对应的水平RecyclerView Adapter,这样点击水平项时就能同时拿到垂直和水平两个位置,进而从你的模型数据里取出完整的条目信息。下面给你几种实用的实现方案:

方案1:自定义接口回调(最经典、通用性强)

思路是在水平Adapter里定义一个点击回调接口,当垂直Adapter绑定数据时,把当前垂直item的位置传递给水平Adapter,同时给水平Adapter设置回调,点击时将垂直+水平位置一起抛出。

水平Adapter代码示例

class HorizontalAdapter(
    private var horizontalData: List<YourHorizontalModel>,
    private var verticalItemPosition: Int, // 保存垂直RecyclerView的当前item位置
    private val onItemClickListener: (verticalPos: Int, horizontalPos: Int) -> Unit
) : RecyclerView.Adapter<HorizontalAdapter.HorizontalViewHolder>() {

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

    override fun onBindViewHolder(holder: HorizontalViewHolder, position: Int) {
        val item = horizontalData[position]
        // 绑定数据到UI(比如设置标题、图片)

        // 给item设置点击事件
        holder.itemView.setOnClickListener {
            // 把垂直和水平位置一起传给上层
            onItemClickListener.invoke(verticalItemPosition, position)
        }
    }

    override fun getItemCount() = horizontalData.size

    class HorizontalViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

垂直Adapter代码示例

class VerticalAdapter(private var verticalData: List<YourVerticalModel>) : RecyclerView.Adapter<VerticalAdapter.VerticalViewHolder>() {

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

    override fun onBindViewHolder(holder: VerticalViewHolder, position: Int) {
        val verticalItem = verticalData[position]
        // 设置垂直item的头部信息(比如分类标题)

        // 初始化水平Adapter,传入当前垂直位置和点击回调
        val horizontalAdapter = HorizontalAdapter(
            verticalItem.horizontalList,
            position,
            onHorizontalItemClicked = { verticalPos, horizontalPos ->
                // 在这里拿到两个位置,直接获取完整数据
                val clickedItem = verticalData[verticalPos].horizontalList[horizontalPos]
                // 处理点击逻辑(比如跳转详情、弹窗提示)
                Toast.makeText(holder.itemView.context, "点击了${clickedItem.title}", Toast.LENGTH_SHORT).show()
            }
        )

        holder.horizontalRv.adapter = horizontalAdapter
        holder.horizontalRv.layoutManager = LinearLayoutManager(holder.itemView.context, LinearLayoutManager.HORIZONTAL, false)
    }

    override fun getItemCount() = verticalData.size

    class VerticalViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val horizontalRv: RecyclerView = itemView.findViewById(R.id.rv_horizontal)
    }
}

方案2:借助ViewModel(适配MVVM架构)

如果你的项目用了MVVM,可以通过ViewModel的LiveData来传递点击事件的位置信息,解耦Adapter和上层页面的逻辑。

ViewModel代码

class HomeViewModel : ViewModel() {
    // 用Pair存储垂直和水平位置
    val horizontalItemClickEvent = MutableLiveData<Pair<Int, Int>>()
}

水平Adapter修改

class HorizontalAdapter(
    private var horizontalData: List<YourHorizontalModel>,
    private var verticalItemPosition: Int,
    private val viewModel: HomeViewModel
) : RecyclerView.Adapter<HorizontalAdapter.HorizontalViewHolder>() {

    override fun onBindViewHolder(holder: HorizontalViewHolder, position: Int) {
        val item = horizontalData[position]
        holder.itemView.setOnClickListener {
            // 把位置信息post到LiveData
            viewModel.horizontalItemClickEvent.postValue(Pair(verticalItemPosition, position))
        }
    }

    // 其他代码和方案1一致
}

页面(Activity/Fragment)中观察事件

viewModel.horizontalItemClickEvent.observe(this) { (verticalPos, horizontalPos) ->
    val clickedItem = verticalData[verticalPos].horizontalList[horizontalPos]
    // 处理点击逻辑
}

方案3:用Tag快速传递(适合临时测试,不推荐长期使用)

如果只是快速验证功能,可以给水平item的View设置Tag,把垂直位置和水平位置存进去,点击时直接取出:

// 水平Adapter的onBindViewHolder中
holder.itemView.setTag(Pair(verticalItemPosition, position))
holder.itemView.setOnClickListener {
    val (verticalPos, horizontalPos) = it.tag as Pair<Int, Int>
    val clickedItem = verticalData[verticalPos].horizontalList[horizontalPos]
}

这种方式虽然简单,但Tag可能引发内存泄漏,不推荐在正式项目中使用。

核心逻辑总结:只要把垂直RecyclerView的item位置传递到对应的水平Adapter中,点击水平项时就能同时拿到两个维度的位置,再从你的模型结构(比如List<VerticalModel>,每个VerticalModel包含List<HorizontalModel>)中提取完整的点击数据。

内容的提问来源于stack exchange,提问作者Vishwanath.M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:04:45