如果该位置的视图在屏幕上不可见或未滚动,则Android Recyclerview notifyItemChanged(position,payLoad)不起作用

时间:2018-06-21 10:17:55

标签: android android-layout kotlin recycler-adapter

我在我的应用中使用RecyclerView,其中itemViewCache包含20个项目,因为我的列表的最大可能大小为20。这是“单个项目选择列表”。现在,当列表加载时,第一个单元格将突出显示为默认选定位置。如果我单击不同位置的单元格,则该位置的视图将被选中并突出显示,同时先前选择的视图将变为白色,即未选中。 当我使用adapter.notifyDataSetChanged(position, payLoad)方法更新列表中的数据时,上面的方法工作正常。但是,当将当前选定位置的单元格滚动出屏幕并尝试选择新位置时,新单元格将突出显示并被选中,因此不会使先前选择的单元格变白。对于位于滚动位置的单元格,系统甚至不调用notifyDataSetChanged(positioin, payLoad)方法在其中创建ui。在我与RecyclerViews一起工作的过程中,任何帮助将不胜感激。

这是我的适配器的代码:

class EventsCalendarAdapter(var eventSectionedFrag: EventSectionedFrag, var arrayList: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.adapter_calendar_months, parent, false)
    return CalendarHolder(view)
}

override fun getItemCount() = arrayList.size


override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>) {
    if (payloads.isNotEmpty()) {
        var bundle = payloads[0] as Bundle
        var isSelected: Boolean? = bundle.getBoolean("selected")
        var setCurrentMonthSelected: Boolean? = bundle.getBoolean("setMonth")


        with(holder) {
            if (isSelected != null) {
                val tvMonth = itemView.findViewById<TextView>(R.id.tv_month)
                tvMonth.apply {
                    setTextColor(ContextCompat.getColor(eventSectionedFrag.activity!!, if (isSelected) R.color.white else R.color.better_than_black))
                    background.setColorFilter(ContextCompat.getColor(eventSectionedFrag.activity!!, if (isSelected) android.R.color.holo_red_light else R.color.white), PorterDuff.Mode.SRC)
                }
            }

            if (setCurrentMonthSelected != null) {
                val view = itemView.findViewById<View>(R.id.view_current)
                view.visibility = if (setCurrentMonthSelected) {
                    View.VISIBLE
                } else {
                    View.INVISIBLE
                }
            }
        }
    } else {
        super.onBindViewHolder(holder, position, payloads)
    }
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val myHolder = holder as CalendarHolder
    myHolder.bindItems(eventSectionedFrag = eventSectionedFrag, month = arrayList[position], position = position)
}

class CalendarHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun bindItems(eventSectionedFrag: EventSectionedFrag, month: String, position: Int) {
        val tvMonth = itemView.findViewById<TextView>(R.id.tv_month)
        val cardMonth = itemView.findViewById<ConstraintLayout>(R.id.card_month)
        val view = itemView.findViewById<View>(R.id.view_current)
        view.visibility = View.INVISIBLE
        val callbacks = eventSectionedFrag as CalendarCallbacks

        tvMonth.text = month
        view.apply {
            visibility = if (callbacks.getCurrentMonthPosition() == position) {
                View.VISIBLE
            } else {
                View.INVISIBLE
            }
        }
        cardMonth.setOnClickListener {
            callbacks.onMonthSelected(adapterPosition, tvMonth)
        }
    }
}

fun addMonths(arrayList: ArrayList<String>) {
    this.arrayList.clear()
    this.arrayList.addAll(arrayList)
    notifyDataSetChanged()
}

interface CalendarCallbacks {
    fun onMonthSelected(position: Int, currentSelectedView: TextView)
    fun getCurrentMonthPosition(): Int
}

}

这是我从活动中调用更改的方式,

override fun notifyCalendar(isCurrentYearSelected: Boolean, position: Int) {
    var bundle = Bundle()
    bundle.putBoolean("setMonth", isCurrentYearSelected)
    calendarAdapter.notifyItemChanged(position, bundle)
}

2 个答案:

答案 0 :(得分:1)

来自RecyclerView.Adapter#notifyItemChanged(int position, java.lang.Object payload) docs

  

适配器不应假定有效载荷将始终传递给onBindViewHolder(),例如当未附加视图时,有效载荷将被简单地丢弃。

因此,当将当前选定位置的单元格滚动出屏幕时,由于旧的选定视图不存在,因此什么都不会改变。

您可以修改arrayList以便在其中存储所选状态,也可以在CalendarCallbacks中添加一种方法来获取当前所选位置,但是必须注意在需要时更改所选位置

答案 1 :(得分:-1)

您误解了ViewHolder模式和notifyItemChanged方法。

ViewHolder-包含视图的对象,当您滚动浏览RecyclerView时,这些对象将被重新使用以减少内存和CPU消耗。它们的目的是显示数据集,在其中保存任何数据通常是不可接受的。

notifyItemChanged-目的是显式更新显示的ViewHolders。您必须在调用此方法之前修改基础数据集(包括所选项目的数组),以便将来使用onBindViewHolder(有效载荷为空)正确显示项目。