RecyclerView在启动时闪烁数据,导致行看不见。

4
在某些设备上,RecyclerView 会闪烁并显示一些项目,然后才会按行出现更多的项目。我无法调试它,因为在模拟器和我的手机上没有发生这种情况。
有人经历过类似的情况吗?

enter image description here

正确的方法是保留以下图片:

enter image description here

我正在SubItemsActivity中创建如下RecyclerView:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    subMainList = ArrayList()

    subMainList = db.listSubItems("AND id_main_item=$mainId")

    layoutManagerRecycler = LinearLayoutManager(this)
    subMainItemsRecycler.layoutManager = layoutManagerRecycler
    subMainItemsRecycler.addItemDecoration(DividerItemDecoration(this, 1))

    var subMainAdapter = SubMainAdapter(this, subMainList, this, activate)
    subMainAdapter.setHasStableIds(true)
    subMainItemsRecycler.adapter = subMainAdapter
}

这里是recyclerView布局:

我有两个ConstraintLayouts,主要的是第一个,id为“prioritize_edit”,另一个id为“prioritize_sub”的布局不会在图像示例中出现。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/prioritize_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/counter"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:textSize="17sp"
            android:textStyle="bold"
            android:textColor="@color/white"
            android:paddingStart="4dp"
            android:paddingEnd="2dp"
            android:paddingVertical="7.5dp"
            android:layout_marginTop="4dp"
            android:layout_marginBottom="1dp"
            android:background="#BFBFBF"
            android:layout_marginStart="8dp"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/arrows"
            app:layout_constraintTop_toTopOf="parent" >
        </TextView>

        <ImageView
            android:id="@+id/arrows"
            android:src="@drawable/icon_arrow_bottom"
            android:layout_height="0dp"
            android:layout_width="15dp"
            android:paddingEnd="1dp"
            android:layout_marginTop="4dp"
            android:layout_marginBottom="1dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/counter"
            app:layout_constraintEnd_toStartOf="@+id/check_item"
            app:layout_constraintTop_toTopOf="parent">

        </ImageView>

        <CheckBox
            android:id="@+id/check_item"
            android:layout_width="30dp"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:layout_gravity="start|center_vertical"
            android:gravity="start|center_vertical"
            android:layout_marginStart="3dp"
            android:layout_marginEnd="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/arrows"
            app:layout_constraintEnd_toStartOf="@+id/color_picker"
            app:layout_constraintTop_toTopOf="parent" />

        <Spinner
            android:id="@+id/color_picker"
            android:layout_width="35dp"
            android:layout_height="wrap_content"
            android:background="@null"
            android:gravity="center"
            android:layout_gravity="center"
            android:layout_marginRight="5dp"
            android:layout_marginEnd="5dp"
            android:layout_marginLeft="13dp"
            android:layout_marginStart="13dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/check_item"
            app:layout_constraintEnd_toStartOf="@+id/list_subitem"
            app:layout_constraintTop_toTopOf="parent" />

        <EditText
            android:id="@+id/list_subitem"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:layout_marginBottom="0dp"
            android:textSize="17sp"
            android:fontFamily="sans-serif-black"
            android:textColor="@color/text_gray"
            android:layout_alignParentStart="true"
            android:layout_alignParentEnd="true"
            app:layout_constrainedWidth="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/color_picker"
            app:layout_constraintEnd_toStartOf="@+id/menu_subitem"
            app:layout_constraintTop_toTopOf="parent" />


        <ImageView
            android:id="@+id/menu_subitem"
            android:layout_width="40dp"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentTop="true"
            android:paddingEnd="8dp"
            android:src="@drawable/round_more_vert_black_36"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/list_subitem"
            app:layout_constraintEnd_toStartOf="@+id/draggable_subitem"
            app:layout_constraintTop_toTopOf="parent"/>

    <ImageView
        android:id="@+id/draggable_subitem"
        android:layout_width="42dp"
        android:layout_height="42dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="10dp"
        android:layout_marginVertical="0dp"
        android:src="@drawable/icon_draggable"
        android:background="@null"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/menu_subitem"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/prioritize_sub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:visibility="visible"
    android:layout_marginBottom="5dp">


    <Button
        android:id="@+id/prioritizer_button"
        android:layout_width="0dp"
        android:layout_height="45dp"
        android:fontFamily="sans-serif-black"
        android:text="@string/prioritize"
        android:textColor="@color/white"
        android:background="@color/colorPrimary"
        android:alpha="0.80"
        android:paddingHorizontal="15dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="15dp"
        android:textSize="16sp"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/counter_invisible"/>

    <TextView
        android:id="@+id/counter_invisible"
        android:visibility="invisible"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:textStyle="bold"
        android:textColor="@color/white"
        android:paddingHorizontal="10dp"
        android:paddingVertical="7.5dp"
        android:layout_marginTop="7dp"
        android:background="#BFBFBF"
        android:layout_marginStart="8dp"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/prioritizer_button"/>


</androidx.constraintlayout.widget.ConstraintLayout>

我的适配器是这个:

class SubMainAdapter(
    var activity: SubMainActivity,
    var items: MutableList<SubItems>,
    var clickListener: OnSubMainItemClickListener,
    var activate: Boolean
) : RecyclerView.Adapter<SubMainViewHolder>(){

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubMainViewHolder {

        val itemView = LayoutInflater.from(parent.context).inflate(
            R.layout.layout_subitem_view,
            parent,
            false
        )
        val viewHolder = SubMainViewHolder(itemView)

        return viewHolder
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onBindViewHolder(holder: SubMainViewHolder, position: Int) {
        holder.initialize(
            activity, items[position], clickListener, items.size,
            items,
            position
        )

        if (activate) {
            holder.dragButton.visibility = View.VISIBLE
            holder.check_item.visibility = View.GONE
            holder.menuButton.visibility = View.GONE
        } else {
            holder.dragButton.visibility = View.GONE
            holder.check_item.visibility = View.VISIBLE
            holder.menuButton.visibility = View.VISIBLE
        }

        holder.dragButton.setOnTouchListener { v, event ->
            if(event.actionMasked== MotionEvent.ACTION_DOWN){
                v.performClick()
                activity.touchHelper?.startDrag(holder)
            }
            false
        }
    }

    override fun getItemId(position: Int): Long {
        val subItems: SubItems = items[position]
        return subItems.id.toLong()
    }

    override fun getItemViewType(position: Int): Int {
        return position
    }
}

class SubMainViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
    var subMainItem = itemView.list_subitem
    var counter = itemView.counter
    var arrows = itemView.arrows
    var counterInvisible = itemView.counter_invisible
    var prioritizeSub = itemView.prioritize_sub
    var prioritizerButton = itemView.prioritizer_button
    var prioritizeEdit = itemView.prioritize_edit
    var check_item = itemView.check_item
    var deleteButton = R.id.trash_subitem
    var menuButton = itemView.menu_subitem
    var dragButton = itemView.draggable_subitem
    var color_picker = itemView.color_picker

    fun initialize(
        activity: SubMainActivity,
        item: SubItems,
        action: OnSubMainItemClickListener,
        sizeArrayItems: Int,
        listItems: MutableList<SubItems>,
        position: Int
    ){
//        var counterValue: String = item.list_order.toString()
//        var digitsNumber: Int = sizeArrayItems.toString().length
//        while (counterValue.length<digitsNumber){
//            counterValue = "0$counterValue"
//        }
        var counterValue: String = item.path_index

        subMainItem.setText(item.sub_item)
        counterInvisible.text = "$counterValue"
        counter.text = "$counterValue"

        counter.setBackgroundColor(Color.parseColor("#a5a5a5"))
        counter.background.alpha = if(item.max_level==0) 0 else (255*item.level)/item.max_level
        arrows.setBackgroundColor(Color.parseColor("#a5a5a5"))
        arrows.background.alpha = if(item.max_level==0) 0 else (255*item.level)/item.max_level

        val prevItem = if(position <= listItems.size){listItems[position]}else{if(position-1 <= listItems.size){listItems[position]}else{listItems[position - 1]}}
        val childs = item.direct_childs
        val nextItem = if(position >= listItems.size){listItems[position]}else{if(position+1 >= listItems.size){listItems[position]}else{listItems[position + 1]}}

        if(childs==0){
            arrows.setImageResource(R.drawable.icon_arrow_right)
        }else{
            if(nextItem.visibility == 0){
                arrows.setImageResource(R.drawable.icon_arrow_right)
            }else {
                arrows.setImageResource(R.drawable.icon_arrow_bottom)
            }
            arrows.setOnClickListener {
                action.toggleSubItems(item, adapterPosition, itemView)
            }
            counter.setOnClickListener {
                action.toggleSubItems(item, adapterPosition, itemView)
            }

        }

        if (item.prioritizeButton){
            prioritizeSub.visibility = View.VISIBLE
            val prioritizeString = activity.getString(R.string.prioritize)
            val finalStr = String.format(prioritizeString, item.path_index)
            prioritizerButton.text = finalStr
            prioritizerButton.setOnClickListener{
                action.onPrioritizeItemsClick(item)
            }
            prioritizeEdit.visibility = View.GONE
        }else{
            prioritizeSub.visibility = View.GONE
            prioritizeEdit.visibility = View.VISIBLE
        }

        val param = itemView.layoutParams as RecyclerView.LayoutParams
        if (item.visibility==1) {
            param.height = LinearLayout.LayoutParams.WRAP_CONTENT
            param.width = LinearLayout.LayoutParams.MATCH_PARENT
            itemView.visibility = View.VISIBLE
        } else {
            itemView.visibility = View.GONE
            param.height = 0
            param.width = 0
        }
        itemView.layoutParams = param


        if (item.checked==Constants.TRUE){
            check_item.isChecked = true
            subMainItem.setTextColor(ContextCompat.getColor(activity, (R.color.checked)))
            counter.setTextColor(ContextCompat.getColor(activity, (R.color.checked)))
            subMainItem.apply {
                paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
            }
            counter.apply {
                paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
            }
        }else{
            check_item.isChecked = false
            subMainItem.setTextColor(ContextCompat.getColor(activity, (R.color.text_grayer)))
            counter.setTextColor(ContextCompat.getColor(activity, (R.color.text_gray_darker)))
            subMainItem.apply {
                paintFlags = paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
            }
            counter.apply {
                paintFlags = paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
            }
        }
        check_item.setOnClickListener{
            action.onCheckItemClick(item, adapterPosition, itemView)
        }

        menuButton.setOnClickListener{
            val popup = PopupMenu(activity, menuButton)
            popup.inflate(R.menu.submain_options)
            popup.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener {
                override fun onMenuItemClick(menuItem: MenuItem): Boolean {
                    when (menuItem.itemId) {
                        R.id.trash_subitem -> {
                            action.onExcludeItemClick(item, adapterPosition)
                            return true
                        }
                        R.id.add_sub_subitem -> {
                            action.onAddChildItemClick(item, adapterPosition)
                            return true
                        }
                        R.id.prioritize_sub_subitem -> {
                            action.manageDragButtons(true, item.id, item.direct_childs)
                            return true
                        }
                        else -> return false
                    }
                }
            })
            popup.show()
        }

        val textWatcher = object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {}
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(
                text: CharSequence?,
                start: Int,
                before: Int,
                count: Int
            ) {
                action.onKeyDownItem(item, itemView, text)
            }
        }
        subMainItem.addTextChangedListener(textWatcher)

        color_picker.adapter = CustomSpinnerAdapter(
            color_picker.context,
            listOf(
                SpinnerData(R.drawable.white_arrow),
                SpinnerData(R.drawable.red_arrow),
                SpinnerData(R.drawable.orange_arrow),
                SpinnerData(R.drawable.yellow_arrow),
                SpinnerData(R.drawable.green_arrow),
                SpinnerData(R.drawable.blue_arrow),
                SpinnerData(R.drawable.turquoise_arrow),
                SpinnerData(R.drawable.purple_arrow)
            )
        )
//        var checkSpinner: Int = 0
        color_picker.isSelected = false;
        color_picker.setSelection(item.color, false)
        color_picker.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(
                adapterView: AdapterView<*>?,
                view: View,
                spinnerPosition: Int,
                l: Long
            ) {
//                if(++checkSpinner > 1) {
                    action.onSpinnerChange(item, spinnerPosition)
//                }
            }

            override fun onNothingSelected(adapterView: AdapterView<*>?) {
                return
            }
        }
    }
}

interface OnSubMainItemClickListener{
    fun onCheckItemClick(item: SubItems, position: Int, view: View)
    fun onExcludeItemClick(item: SubItems, position: Int)
    fun onAddChildItemClick(item: SubItems, position: Int)
    fun onPrioritizeItemsClick(item: SubItems)
    fun onKeyDownItem(item: SubItems, view: View, text: CharSequence?)
    fun onChangeItem(item: SubItems, view: View, text: CharSequence?)
    fun onSpinnerChange(item: SubItems, spinnerPosition: Int)
    fun manageDragButtons(activate: Boolean, parentId: Int, childs: Int)
    fun toggleSubItems(item: SubItems, position: Int, view: View)
}

由于我正在使用setHasStableIds(true),因此我已尝试更改适配器中的getItemId函数,但问题仍然存在。是否有人遇到过类似的问题?

2个回答

5

我在使用spinner的OnItemSelectedListener时遇到了问题。由于OnItemSelectedListener在创建时会被首次调用,导致其中的函数总是调用数据库列表,为了解决这个问题,我在Adapter中取消注释了checkSpinner变量,以防止首次调用,现在问题已经得到了解决。

    var checkSpinner: Int = 0
    color_picker.isSelected = false;
    color_picker.setSelection(item.color, false)
    color_picker.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
        override fun onItemSelected(
            adapterView: AdapterView<*>?,
            view: View,
            spinnerPosition: Int,
            l: Long
        ) {
            if(++checkSpinner > 1) {
                action.onSpinnerChange(item, spinnerPosition)
            }
        }

        override fun onNothingSelected(adapterView: AdapterView<*>?) {
            return
        }
    }

1

onBindViewHolder() 将绘制视图。在默认情况下,您可以在xml文件中查看许多视图。所有将被可见性切换的视图必须在xml中默认为gone或invisible。一旦加载视图,onBindViewHolder() 可以控制其可见性。

问题是,Recycler 在 onCreateViewHolder() 中填充视图并使其可见。之后设置数据并调用 notifyDataSetChanged。这将根据 onBindViewHolder() 函数中的条件更新视图。但是,在此之前,您会看到这些视图。由于这需要一点时间,因此您会看到闪烁。

这将发生在内存较低或处理速度较慢的设备上。


Mohit,你所说的问题看起来像是暂时性的不可见行,这些行在一段时间后无法正确加载? - alexandre9865
那是闪烁问题。视图加载后,您会看到视图,然后将数据添加到列表并调用通知。这就是您看到闪烁的原因。 - Mohit Ajwani
理论上,如果我在 prioritize_sub 项目上放置一个 visibility gone,那么它会起作用吗? - alexandre9865
1
让我们在聊天中继续这个讨论 - Mohit Ajwani
我又再次呼叫了你。 - alexandre9865
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接