【问题标题】:RecyclerView not updating size after setData() with notifyDataSetChanged使用 notifyDataSetChanged 在 setData() 之后 RecyclerView 未更新大小
【发布时间】:2021-10-22 09:34:30
【问题描述】:

预期的行为是具有互斥的多个下拉菜单。

例如,我有:

  • 数组 = [“A”、“B”、“C”、“D”、“E”]
  • 菜单1
  • 菜单2
  • 菜单3

如果我在 menu1 中选择“A”,那么在 menu2 和 menu3 中“A”就不必出现了。

MainActivity

class MainActivity : AppCompatActivity() {

    private lateinit var scdd1: SingleCheckBoxDropDown
    private lateinit var scdd2: SingleCheckBoxDropDown
    private lateinit var scdd3: SingleCheckBoxDropDown

    private val strArr = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        strArr.add("string 1")
        strArr.add("string 2")
        strArr.add("string 3")
        strArr.add("string 4")
        strArr.add("string 5")

        /**
         * =============
         * Single Select
         * =============
         */
        /*val scdd: SingleCheckBoxDropDown = findViewById(R.id.scdd1)
        scdd.setData(strArr)

        val tv1: TextView = findViewById(R.id.tv1)

        scdd.setOnItemClickListenerWithSingleSelect {
            val checked = scdd.getChecked()
            if (checked != -1)
                tv1.text = strArr[checked]
        }*/

        /**
         * ====================================
         * Single Select with Mutual Exclusion
         * ====================================
         */
        scdd1 = findViewById(R.id.category1)
        scdd2 = findViewById(R.id.category2)
        scdd3 = findViewById(R.id.category3)

        scdd1.setData(strArr)
        scdd2.setData(strArr)
        scdd3.setData(strArr)

        /** 1 */
        scdd1.setOnItemClickListenerWithSingleSelect {
            val filter1 = scdd1.getCheckedStr()
            val filter2 = scdd2.getCheckedStr()
            val filter3 = scdd3.getCheckedStr()

            scdd1.setAnswer(filter1)

            val data2 = strArr.filter { it != filter1 && it != filter3 }
            val data3 = strArr.filter { it != filter1 && it != filter2 }

            scdd2.setData(data2)
            scdd3.setData(data3)

            scdd1.setChecked(filter1)
            scdd2.setChecked(filter2)
            scdd3.setChecked(filter3)
        }

        /** 2 */
        scdd2.setOnItemClickListenerWithSingleSelect {
            val filter1 = scdd1.getCheckedStr()
            val filter2 = scdd2.getCheckedStr()
            val filter3 = scdd3.getCheckedStr()

            scdd2.setAnswer(filter2)

            val data1 = strArr.filter { it != filter2 && it != filter3 }
            val data3 = strArr.filter { it != filter1 && it != filter2 }

            scdd1.setData(data1)
            scdd3.setData(data3)

            scdd1.setChecked(filter1)
            scdd2.setChecked(filter2)
            scdd3.setChecked(filter3)
        }

        /** 3 */
        scdd3.setOnItemClickListenerWithSingleSelect {
            val filter1 = scdd1.getCheckedStr()
            val filter2 = scdd2.getCheckedStr()
            val filter3 = scdd3.getCheckedStr()

            scdd3.setAnswer(filter3)

            val data1 = strArr.filter { it != filter2 && it != filter3 }
            val data2 = strArr.filter { it != filter1 && it != filter3 }

            scdd1.setData(data1)
            scdd2.setData(data2)

            scdd1.setChecked(filter1)
            scdd2.setChecked(filter2)
            scdd3.setChecked(filter3)
        }

        /**
         * Bug 1
         *
         * [x] 1            [ ] 1
         * [ ] 4    -->     [x] 4
         * [ ] 5            [ ] 5
         *
         * [x] 2            [x] 1
         * [ ] 4            [ ] 2
         * [ ] 5            [ ] 5
         *
         * [x] 3            [x] 1
         * [ ] 4            [ ] 3
         * [ ] 5            [ ] 5
         */

    }

}

activity_main.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#002E2A"
    android:gravity="center_horizontal"
    android:padding="20dp"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
            android:id="@+id/category1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv1"
            app:my_string_entries="@array/arr_str"
            app:question="Category 1" />

        <jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
            android:id="@+id/category2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/category1"
            app:my_string_entries="@array/arr_str"
            app:question="Category 2" />

        <jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
            android:id="@+id/category3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/category2"
            app:my_string_entries="@array/arr_str"
            app:question="Category 3" />

    </RelativeLayout>

</ScrollView>

SingleCheckBoxDropDown

class SingleCheckBoxDropDown @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {

    private val scddContainer: RelativeLayout
    private val dropdownMenu: RecyclerView
    private val questionTV: TextView
    private val answerTV: TextView
    private var adapter: ScddAdapter

    init {
        LayoutInflater.from(context)
            .inflate(R.layout.scdd, this, true) // true

        /** GET CUSTOM ATTRIBUTES */
        val typedArr = context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.SingleCheckBoxDropDown,
            defStyleAttr,
            0
        )

        val question = typedArr.getString(R.styleable.SingleCheckBoxDropDown_question)
        val charSequenceArr: Array<CharSequence> =
            typedArr.getTextArray(R.styleable.SingleCheckBoxDropDown_my_string_entries)

        scddContainer = findViewById(R.id.scdd_container)
        dropdownMenu = findViewById(R.id.dropdown_menu)
        answerTV = findViewById(R.id.answer)
        questionTV = findViewById(R.id.question)
        questionTV.text = question


        scddContainer.setOnClickListener {
            if (dropdownMenu.visibility == View.GONE)
                dropdownMenu.visibility = View.VISIBLE
            else dropdownMenu.visibility = View.GONE
        }

        adapter = ScddAdapter()
        adapter.addAll(charSequenceArr)
        dropdownMenu.layoutManager = LinearLayoutManager(context)
        dropdownMenu.adapter = adapter
    }

    fun resetHard(data: List<String>) {
        adapter = ScddAdapter()
        adapter.addAll(data.toTypedArray())
        dropdownMenu.adapter = adapter
    }

    fun setData(strArr: List<String>) {

        /** bug 1 - hide bug */
        // dropdownMenu.removeAllViews()
        // dropdownMenu.removeAllViewsInLayout()

        adapter.setData(strArr as ArrayList<String>)

        // RecyclerView won't update view after data change.
        Log.i("try", "strArr size: ${strArr.size}")
        Log.i("try", "dropdownmenu size: ${dropdownMenu.size}")

    }

    fun setAnswer(filter: CharSequence) {
        answerTV.text = filter
    }

    fun getCheckedStr(): CharSequence {
        return adapter.getCheckedStr()
    }

    fun getChecked(): Int {
        return adapter.getChecked()
    }

    /**
     * Single Select Core
     */
    fun setOnItemClickListenerWithSingleSelect(function: () -> Unit) {
        adapter.setOnItemClickListener {
            for (i in 0 until dropdownMenu.size)
                if (i != it)
                        (dropdownMenu[i] as CheckBox).isChecked = false
            function()
        }
    }

    /** bug 1 - fix part 1 */
    fun setChecked(filter: CharSequence) {
        for (i in 0 until dropdownMenu.size) {
            (dropdownMenu[i] as CheckBox).isChecked = false
            if ((dropdownMenu[i] as CheckBox).text == filter) {
                (dropdownMenu[i] as CheckBox).isChecked = true
                // adapter.notifyItemChanged(i)
            }
        }

     }
}

scdd.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@android:color/transparent"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:id="@+id/scdd_container"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@android:color/holo_green_dark"
        android:clickable="true"
        android:focusable="true"
        android:gravity="center_vertical">
        <TextView
            android:id="@+id/question"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:textColor="@android:color/white"
            android:textSize="12sp"
            tools:text="The Question" />

        <TextView
            android:id="@+id/answer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:gravity="end"
            android:textColor="@android:color/white"
            tools:text="The Answer" />
    </RelativeLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/dropdown_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/scdd_container"
        android:background="@android:color/holo_green_light"
        android:translationZ="999dp"
        android:visibility="visible" />

</RelativeLayout>

ScddAdapter

/** ADAPTER */
class ScddAdapter : RecyclerView.Adapter<ScddAdapter.ScddViewHolder>() {

    /** VIEW HOLDER */
    class ScddViewHolder(view: View) :
        RecyclerView.ViewHolder(view) {
        val cb: CheckBox = view.findViewById(R.id.cb)
    }

    private var callback = { }
    private var list = ArrayList<CharSequence>()
    private var checked: Int = -1
    private var checkedStr = ""

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScddViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_single_checkbox, parent, false) // false
        return ScddViewHolder(view)
    }

    override fun onBindViewHolder(holder: ScddViewHolder, position: Int) {
        holder.cb.text = list[position]
        holder.itemView.setOnClickListener {
            if(holder.cb.isChecked) {
                checkedStr = holder.cb.text as String
                checked = holder.layoutPosition
            }
            else {
                checkedStr = ""
                checked = -1
            }
            this.callback()
        }
    }

    override fun getItemCount(): Int {
        return list.size
    }

    fun addAll(charSequenceArr: Array<CharSequence>) {
        list.addAll(charSequenceArr)
    }

    fun setData(datas: ArrayList<String>) {
        // for (i in 0 until strArr.size) Log.i("try", strArr[i])
        list.clear()
        notifyDataSetChanged()
        this.list.addAll(datas)
        notifyDataSetChanged()
    }

    fun getChecked(): Int {
        return checked
    }

    fun getCheckedStr(): CharSequence {
        return checkedStr
    }

    fun setOnItemClickListener(function: (holderPosition: Int) -> Unit) {
        this.callback = {
            function(checked)
        }
    }

}

item_single_checkbox.xml

<CheckBox
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="?android:attr/spinnerItemStyle"
    tools:text="hello"
    android:id="@+id/cb"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textColor="@color/white"
    android:background="@android:color/background_dark"
    android:buttonTint="@color/white"
    android:textAlignment="inherit"/>

我注意到的问题是在 SingleCheckBoxDropDown 的 setData() 中:

Log.i("try", "strArr size: ${strArr.size}")
Log.i("try", "dropdownmenu size: ${dropdownMenu.size}")

我的 RecyclerView(下拉菜单)没有返回正确的大小,我知道为什么。

【问题讨论】:

  • 你在这里期待什么?

标签: android kotlin android-recyclerview notifydatasetchanged


【解决方案1】:

这似乎是因为您的适配器的addAll() 方法没有通知更改。

尝试将其更改为:

fun addAll(charSequenceArr: Array<CharSequence>) {
    val oldSize = getItemCount();
    list.addAll(charSequenceArr)
    notifyItemRangeInserted(oldSize, charSequenceArr.size())
}

另外,在setData() 中,您只能在末尾调用notifyDataSetChanged()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多