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

Kotlin实现RecyclerView展开新项时自动折叠已展开项相关问题

解答

疑问解答

    1. 为什么previousPosition需要初始化为-1?
      RecyclerView的条目索引从0开始计数,初始状态下没有任何处于展开状态的条目,-1是约定的「无有效展开条目」的标记值,不会和真实的条目索引产生冲突。
    1. 如何区分currentPosition和previousPosition,并将previousPosition存储为独立的对象和值?
      不需要复杂对象存储,直接在ProductAdapter中定义一个Int类型的成员变量previousExpandedPosition即可,专门用来记录上一次展开条目的索引;每次点击条目时,当前被点击条目的索引就是currentPosition,二者直接对比即可。
    1. 如果previousPosition方案可行,我该如何将其集成到现有项目中?
      仅需修改ProductAdapter的逻辑即可,无需改动其他层代码,修改点如下:
    2. 新增成员变量记录上一次展开的位置
    3. 调整条目点击事件的逻辑,先处理旧条目的折叠,再处理当前条目的展开/折叠
    4. 更新记录的展开位置
    1. 是否可以提供相关参考资源?
      下面直接提供适配你现有代码的修改后版本,可直接复制使用。

修改后可运行代码

ProductAdapter.kt

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView

class ProductAdapter(private val productList : ArrayList<Product>) : RecyclerView.Adapter<ProductAdapter.MyViewHolder>() {
    // 新增:记录上一次展开的条目的索引,初始为-1代表无展开条目
    private var previousExpandedPosition = -1

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


    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentItem = productList[position]

        holder.tvProductName.text = currentItem.name
        holder.tvProductCategory.text= currentItem.category
        holder.tvProductQuantity.text=currentItem.quantity
        holder.tvProductPrice.text= "RM "+currentItem.price

        val isVisible : Boolean = currentItem.visibility
        holder.constraintLayout.visibility = if (isVisible) View.VISIBLE else View.GONE

        holder.tvProductName.setOnClickListener{
            // 取当前条目的真实索引,避免ViewHolder复用导致的position错乱
            val currentPosition = holder.absoluteAdapterPosition
            // 如果之前有展开的条目,且不是当前点击的条目,先折叠之前的
            if (previousExpandedPosition >= 0 && previousExpandedPosition != currentPosition) {
                productList[previousExpandedPosition].visibility = false
                notifyItemChanged(previousExpandedPosition)
            }
            // 切换当前条目的展开状态
            currentItem.visibility = !currentItem.visibility
            // 更新记录的展开位置:当前条目变为展开就存当前索引,变为折叠就重置为-1
            previousExpandedPosition = if (currentItem.visibility) currentPosition else -1
            notifyItemChanged(currentPosition)
        }
    }


    override fun getItemCount(): Int = productList.size

    class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
        val tvProductName: TextView = itemView.findViewById(R.id.productName)
        val tvProductCategory : TextView = itemView.findViewById(R.id.productCategory)
        val tvProductQuantity : TextView = itemView.findViewById(R.id.productQuantity)
        val tvProductPrice : TextView = itemView.findViewById(R.id.productPrice)
        val constraintLayout : ConstraintLayout = itemView.findViewById(R.id.expandedLayout)
    }
}

其余Product.kt和ViewPartActivity.kt代码无需改动,替换Adapter后即可实现单次仅展开一个条目的效果。


内容的提问来源于stack exchange,提问作者Low Jung Xuan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 03:24:06