点击按钮添加RecyclerView项不显示问题排查及优化咨询
问题描述
我正在构建一个包含RecyclerView的布局,每个项横向排列三个EditText,点击按钮时期望添加新项。目前点击添加按钮后,新增项不可见,但添加按钮会下移。
相关代码
Adapter类
class AddProjectAdapter(private val itemsList : ArrayList<ItemDetails>) : RecyclerView.Adapter<AddProjectAdapter.AddProjectViewHolder>() { inner class AddProjectViewHolder(private val binding : AddProjectItemViewBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item : ItemDetails){ binding.item = item } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddProjectViewHolder{ return AddProjectViewHolder(AddProjectItemViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } override fun onBindViewHolder(holder: AddProjectViewHolder, position: Int) { holder.bind(itemsList[position]) } override fun getItemCount(): Int = itemsList.size }
列表项布局(add_project_item_view.xml)
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="item" type="com.example.hero.models.ItemDetails" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.card.MaterialCardView android:id="@+id/item_name_cardview" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:flow_horizontalBias="3" app:cardBackgroundColor="@color/light_background" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="@id/g_v_1" android:layout_marginRight="5dp"> <EditText android:id="@+id/item_name_edittext" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Item Name" android:text="@={item.itemName}" android:textColor="@color/t_dark" android:fontFamily="@font/metropolislight" android:textSize="14dp" android:textColorHint="@color/t_dark" android:background="@null" android:padding="10dp" /> </com.google.android.material.card.MaterialCardView> <com.google.android.material.card.MaterialCardView android:id="@+id/rate_unit_cardview" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:flow_horizontalBias="2" android:layout_marginRight="5dp" app:cardBackgroundColor="@color/light_background" app:layout_constraintStart_toEndOf="@id/g_v_1" app:layout_constraintEnd_toEndOf="@id/g_v_2"> <EditText android:id="@+id/rate_unit_edittext" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Rate/Unit" android:text="@={item.rate}" android:textColorHint="@color/t_dark" android:textColor="@color/t_dark" android:fontFamily="@font/metropolislight" android:textSize="14dp" android:padding="10dp" android:background="@null" /> </com.google.android.material.card.MaterialCardView> <com.google.android.material.card.MaterialCardView android:id="@+id/unit_cardview" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:flow_horizontalBias="2" app:cardBackgroundColor="@color/light_background" app:layout_constraintStart_toEndOf="@id/g_v_2" app:layout_constraintEnd_toEndOf="parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/unit_textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:background="@null" android:fontFamily="@font/metropolislight" android:hint="Unit" android:padding="10dp" android:text="@={item.unit}" android:textColor="@color/t_dark" android:textColorHint="@color/t_dark" android:textSize="14dp" /> <ImageView android:id="@+id/drop_down_imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:src="@drawable/dropdown" android:layout_centerVertical="true" /> </RelativeLayout> </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id="@+id/g_v_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.4" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/g_v_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.8" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
所在Activity代码
private val itemsList : ArrayList<ItemDetails> = ArrayList() private lateinit var addProjectAdapter: AddProjectAdapter private lateinit var binding: ActivityAddProjectBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityAddProjectBinding.inflate(layoutInflater) setContentView(binding.root) setAdapter() setListner() } private fun setAdapter(){ addProjectAdapter = AddProjectAdapter(itemsList) binding.itemDetailsRecyclerview.apply { layoutManager = LinearLayoutManager(this@AddProject) adapter = addProjectAdapter } } override fun onClick(v : View?) { when(v?.id){ binding.addItemButton.id - itemsList.add(ItemDetails()) addProjectAdapter.notifyItemInserted(itemsList.size-1) } } } private fun setListner(){ binding.addItemButton.setOnClickListener(this) }
数据类
data class ItemDetails( var itemName : String = "", var rate : String = "", var unit : String = "")
问题排查与修复
1. 列表项布局高度错误
列表项根布局ConstraintLayout的高度设为match_parent,导致每个项占据RecyclerView的全部高度,新项被挤出屏幕。修改为wrap_content:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content">
2. 点击事件语法错误
onClick方法中when分支的箭头写错,导致点击逻辑未执行。修正后:
override fun onClick(v : View?) { when(v?.id){ binding.addItemButton.id -> { itemsList.add(ItemDetails()) addProjectAdapter.notifyItemInserted(itemsList.size-1) } } }
3. 初始无数据问题
首次进入页面时列表为空,建议初始化时添加一个默认项:
private fun setAdapter(){ if(itemsList.isEmpty()){ itemsList.add(ItemDetails()) } addProjectAdapter = AddProjectAdapter(itemsList) binding.itemDetailsRecyclerview.apply { layoutManager = LinearLayoutManager(this@AddProject) adapter = addProjectAdapter } }
更优实现方案
1. 用DiffUtil优化列表更新
避免直接调用notifyItemInserted,改用DiffUtil实现高效更新:
class AddProjectAdapter(private var itemsList: List<ItemDetails>) : RecyclerView.Adapter<AddProjectAdapter.AddProjectViewHolder>() { inner class AddProjectViewHolder(private val binding : AddProjectItemViewBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item : ItemDetails){ binding.item = item } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddProjectViewHolder{ return AddProjectViewHolder(AddProjectItemViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } override fun onBindViewHolder(holder: AddProjectViewHolder, position: Int) { holder.bind(itemsList[position]) } override fun getItemCount(): Int = itemsList.size fun updateItems(newItems: List<ItemDetails>) { val diffResult = DiffUtil.calculateDiff(ItemDiffCallback(itemsList, newItems)) itemsList = newItems diffResult.dispatchUpdatesTo(this) } inner class ItemDiffCallback(private val oldList: List<ItemDetails>, private val newList: List<ItemDetails>) : DiffUtil.Callback() { override fun getOldListSize() = oldList.size override fun getNewListSize() = newList.size override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition] === newList[newItemPosition] } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition] == newList[newItemPosition] } } }
Activity中修改点击逻辑:
override fun onClick(v : View?) { when(v?.id){ binding.addItemButton.id -> { val newList = ArrayList(itemsList).apply { add(ItemDetails()) } addProjectAdapter.updateItems(newList) binding.itemDetailsRecyclerview.scrollToPosition(newList.size - 1) } } }
2. 布局优化
- 移除无效的
flow_horizontalBias属性(ConstraintLayout不支持该属性) - 将Unit的TextView替换为AutoCompleteTextView,保持交互一致性
- 给MaterialCardView添加圆角和阴影提升视觉效果
3. ViewModel管理数据
避免配置变更导致数据丢失,用ViewModel托管列表数据:
class AddProjectViewModel : ViewModel() { val itemsList = MutableLiveData<ArrayList<ItemDetails>>() init { itemsList.value = arrayListOf(ItemDetails()) } fun addNewItem() { val currentList = itemsList.value ?: arrayListOf() currentList.add(ItemDetails()) itemsList.postValue(currentList) } }
Activity中观察数据:
private lateinit var viewModel: AddProjectViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityAddProjectBinding.inflate(layoutInflater) setContentView(binding.root) viewModel = ViewModelProvider(this)[AddProjectViewModel::class.java] setAdapter() setListner() viewModel.itemsList.observe(this) { newList -> addProjectAdapter.updateItems(newList) } } override fun onClick(v : View?) { when(v?.id){ binding.addItemButton.id -> { viewModel.addNewItem() } } }
内容的提问来源于stack exchange,提问作者Panchumarthi Abhinav
相关产品推荐
相关产品推荐

