android - StaggeredGridLayoutManager 中 itemTouchHelperCallback 中的困惑图 block

标签 android kotlin android-recyclerview staggered-gridview

我正在使用 StaggeredGridLayoutManager在我的代码中。
先看看这个:
my
我面临这些问题:

In 1st attempt, I move the tile '1' directly upwards by one step and then stop. Everything looks good and the tile labled as '1' replaces label '2'.


In 2nd attempt, I drag the tile labeled '3' up but do not stop. Still it automatically gets replaced by '1' which is present just above '3'. Something is trouble here.


In my 3rd and 4th attempt, I try to drag my tile up & sideways. Once I do it the tile automatically gets right shifted and out of the frame(even though my touch is still holding it). It can be visible only when I drag it left. Weird!


现在看看我的代码
在我的 MainActivity 的 onCreateMethod
val layoutmanager = StaggeredGridLayoutManager(if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 3 
                                              else 2, StaggeredGridLayoutManager.VERTICAL)
layoutmanager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
recyclerView.layoutManager = layoutmanager
noteAdapter = NoteAdapter(myList, this)
recyclerView.adapter = noteAdapter
我的 ItemTouchHelperCallback方法
private val itemTouchHelperCallback =
            object :
                    ItemTouchHelper.SimpleCallback(0, 0
                    ) {

                override fun isLongPressDragEnabled(): Boolean {
                    return true
                }

                override fun isItemViewSwipeEnabled(): Boolean {
                    return true
                }

                override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
                    val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or
                            ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
                    val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
                    return makeMovementFlags(dragFlags, swipeFlags)
                }

                override fun onMove(
                        recyclerView: RecyclerView,
                        viewHolder: RecyclerView.ViewHolder,
                        target: RecyclerView.ViewHolder
                ): Boolean {
                    val fromPosition = viewHolder.adapterPosition
                    val toPosition = target.adapterPosition

                    if (fromPosition < toPosition) {
                        for (i in fromPosition until toPosition) {
                            Collections.swap(myList, i, i + 1)
                        }
                    } else {
                        for (i in fromPosition downTo toPosition + 1) {
                            Collections.swap(myList, i, i - 1)
                        }
                    }
                    noteAdapter.notifyItemMoved(fromPosition, toPosition)


                    return false
                }
                override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                    
                }

            }
更新
@Zain 发现真正的问题隐藏在我的 NoteAdapter.java 中。 ,所以我强调错误的方法。检查他的答案。
 @Override
    public int getItemViewType(int position) {
        return position;
    }

最佳答案

问题:
getItemViewType() 返回项目位置的RecyclerView适配器;而您只有一种项目 View 类型。
简短回答:
你不应该覆盖 getItemViewType()将其保持为默认值,或者您可以使其返回 0 以指示适配器存在单个 View 类型。

长答案:
当适配器第一次附加到 RecyclerView 时,RecyclerView 的 LayoutManager 需要知道每个 item 位置的布局类型;并为此调用 getItemViewType(position)适配器中的每个位置;所以如果适配器列表有 10 个项目,那么它会被调用 10 次;每次调用它时,它都会返回这个特定项目的类型。
getItemViewType(position)未覆盖所有项的返回值为 0;这表明所有项目都具有相同的类型。
通过在返回 0 时记录它:

2021-01-13 11:05:25.941 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:05:25.950 : onBindViewHolder: Pos: 0
2021-01-13 11:05:25.954 : getItemViewType:  Pos = 1 Return: 0
2021-01-13 11:05:25.959 : onBindViewHolder: Pos: 1
2021-01-13 11:05:25.962 : getItemViewType:  Pos = 2 Return: 0
2021-01-13 11:05:25.970 : onBindViewHolder: Pos: 2
2021-01-13 11:05:25.974 : getItemViewType:  Pos = 3 Return: 0
2021-01-13 11:05:25.979 : onBindViewHolder: Pos: 3
2021-01-13 11:05:25.982 : getItemViewType:  Pos = 4 Return: 0
2021-01-13 11:05:25.988 : onBindViewHolder: Pos: 4
2021-01-13 11:05:26.000 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:05:26.001 : getItemViewType:  Pos = 1 Return: 0
2021-01-13 11:05:26.001 : getItemViewType:  Pos = 2 Return: 0
2021-01-13 11:05:26.001 : getItemViewType:  Pos = 3 Return: 0
2021-01-13 11:05:26.001 : getItemViewType:  Pos = 4 Return: 0
但是当你改为返回 position来自 getItemViewType(position) ;那么您拥有的项目类型与您拥有的职位数量一样多(即列表的大小)。
这种情况下的日志:
2021-01-13 11:11:30.123 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:11:30.145 : onBindViewHolder: Pos: 0
2021-01-13 11:11:30.149 : getItemViewType:  Pos = 1 Return: 1
2021-01-13 11:11:30.160 : onBindViewHolder: Pos: 1
2021-01-13 11:11:30.164 : getItemViewType:  Pos = 2 Return: 2
2021-01-13 11:11:30.172 : onBindViewHolder: Pos: 2
2021-01-13 11:11:30.175 : getItemViewType:  Pos = 3 Return: 3
2021-01-13 11:11:30.179 : onBindViewHolder: Pos: 3
2021-01-13 11:11:30.183 : getItemViewType:  Pos = 4 Return: 4
2021-01-13 11:11:30.190 : onBindViewHolder: Pos: 4
2021-01-13 11:11:30.199 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:11:30.199 : getItemViewType:  Pos = 1 Return: 1
2021-01-13 11:11:30.200 : getItemViewType:  Pos = 2 Return: 2
2021-01-13 11:11:30.200 : getItemViewType:  Pos = 3 Return: 3
2021-01-13 11:11:30.200 : getItemViewType:  Pos = 4 Return: 4
现在RecyclerView处于稳定状态(即填充了所有项目),我们将拖动一个项目并将其放在另一个项目上。
现在我们将 Note no.1 替换为 3(即将位置 4 替换为适配器中的位置 2)getItemViewType()时的日志返回 0
2021-01-13 11:14:26.620 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:14:26.620 : getItemViewType:  Pos = 1 Return: 0
2021-01-13 11:14:26.620 : getItemViewType:  Pos = 2 Return: 0
2021-01-13 11:14:26.621 : getItemViewType:  Pos = 3 Return: 0
2021-01-13 11:14:26.621 : getItemViewType:  Pos = 4 Return: 0
这里 getItemViewType每个位置只调用一次,那是因为您只有一个 View 类型。并且没有调用 onBindViewHolder正如我们刚才所说的 notifyItemMoved使RecyclerView只有调用获取缓存/回收版本,因为在这种情况下所有 View 类型都是相同的。getItemViewType()时的日志返回 position
2021-01-13 11:12:13.659 : getItemViewType:  Pos = 0 Return: 0
2021-01-13 11:12:13.660 : getItemViewType:  Pos = 1 Return: 1
2021-01-13 11:12:13.660 : getItemViewType:  Pos = 2 Return: 2
2021-01-13 11:12:13.660 : getItemViewType:  Pos = 2 Return: 2
2021-01-13 11:12:13.665 : onBindViewHolder: Pos: 2
2021-01-13 11:12:13.667 : getItemViewType:  Pos = 3 Return: 3
2021-01-13 11:12:13.668 : getItemViewType:  Pos = 3 Return: 3
2021-01-13 11:12:13.673 : onBindViewHolder: Pos: 3
2021-01-13 11:12:13.675 : getItemViewType:  Pos = 4 Return: 4
2021-01-13 11:12:13.675 : getItemViewType:  Pos = 4 Return: 4
2021-01-13 11:12:13.681 : onBindViewHolder: Pos: 4
这里 getItemViewType被多次调用,因为每个项目都有其唯一的 View 类型,它需要重新计算该 View 类型,并使用 onBindViewHolder 重新绘制(或重新计算布局)项目对于from (第 2 项)和 to (项目 4)项目和中间项目(项目 3)。
使这些多个 View 类型使您无法完成拖动(可能是由于新的布局重新计算),并且也让中间的 Views 无法在拖放项之间切换。

关于android - StaggeredGridLayoutManager 中 itemTouchHelperCallback 中的困惑图 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65578247/

相关文章:

android - ICS 上的 eglCreateWindowSurface,并从 2D 切换到 3D

android - 具有各种屏幕尺寸的自定义评分栏

kotlin - 在 indexOf(...) 中返回 -1 而不是 null 有什么好处?

android - 动态设置 recyclerview/cardview 背景颜色

android - 使用软键盘上的 Next 键滚动到列表中的下一个项目

Android和数据存储空间?

android - RecyclerView - 字母索引未出现

安卓 Kotlin : Error when using 'suspend' in DAO - Following CodeLabs guide

android - RecyclerView Multiple View types (View Holders) 处理项目选择计数状态

android - 在 Android 中使用网格布局管理器为 Recyclerview 自定义项目装饰