【问题标题】:Jumbled tiles in itemTouchHelperCallback in StaggeredGridLayoutManagerStaggeredGridLayoutManager 中 itemTouchHelperCallback 中的混乱图块
【发布时间】:2021-01-05 11:46:34
【问题描述】:

我在我的代码中使用StaggeredGridLayoutManager

先看看这个:

我面临这些问题:

在第一次尝试中,我将磁贴“1”直接向上移动了一步,然后停止。一切看起来都不错,标记为“1”的图块替换了标签“2”。

在第二次尝试中,我向上拖动标有“3”的图块,但不要停止。它仍然会自动被“3”上方的“1”替换。这里出了点问题。

在我的第 3 次和第 4 次尝试中,我尝试将我的图块向上和横向拖动。一旦我这样做了,瓷砖就会自动右移并移出框架(即使我的触摸仍然握着它)。只有当我向左拖动它时才能看到它。奇怪!

现在看看我的代码

在我的 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;
    }

【问题讨论】:

  • 如果你能在 Github 上提供一个演示项目,我们可以很容易地重现问题,这样我们就不会花任何时间在项目设置上。
  • 我已经在github上上传了这个项目。您可以使用此提交下载:github.com/anandarpit/Notify/tree/… 谢谢! @HarisDautović

标签: android kotlin android-recyclerview staggered-gridview


【解决方案1】:

问题:

RecyclerView适配器的getItemViewType()返回项目位置;而您只有一种项目视图类型。

简答:

您不应覆盖 getItemViewType() 以将其保持为默认值,或者您可以使其返回 0 以指示适配器存在单一视图类型。

长答案:

当适配器第一次附加到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

但是当你从getItemViewType(position)返回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 对每个位置只调用一次,这是因为您只有一个视图类型。并且没有对 onBindViewHolder 的调用,因为我们刚刚调用了 notifyItemMoved,因此 RecyclerView 仅调用获取缓存/回收版本,因为在这种情况下所有视图类型都是相同的。

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 被多次调用,因为每个项目都有其唯一的视图类型,它需要重新计算该视图类型,并使用onBindViewHolder 为@987654344 重新绘制(或重新计算布局)项目@(第 2 项)和 to(第 4 项)项和中间项(第 3 项)。

使这些多个视图类型无法完成拖动(可能是由于新的布局重新计算),也让中间的视图无法在拖放的项之间切换。

【讨论】:

  • 嗯,非常感谢您走到这一步并找出错误。很少有人这样做。我将使用 NoteAdapter 的错误部分更新我的问题。太好了!!!
猜你喜欢
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 2017-07-23
  • 2016-09-20
  • 2023-03-26
  • 2012-05-19
  • 1970-01-01
  • 2020-11-17
相关资源
最近更新 更多