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

点击按钮添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 00:50:27