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

