RecyclerView.Adapter.notifyItemMoved(0,1) scrolls

2020-02-10 06:26发布

I have a RecyclerView managed by a LinearlayoutManager, if I swap item 1 with 0 and then call mAdapter.notifyItemMoved(0,1), the moving animation causes the screen to scroll. How can I prevent it?

3条回答
够拽才男人
2楼-- · 2020-02-10 06:50

Call scrollToPosition(0) after moving items. Unfortunately, i assume, LinearLayoutManager tries to keep first item stable, which moves so it moves the list with it.

查看更多
叼着烟拽天下
3楼-- · 2020-02-10 06:51

Translate @Andreas Wenger's answer to kotlin:

val firstPos = manager.findFirstCompletelyVisibleItemPosition()
var offsetTop = 0
if (firstPos >= 0) {
    val firstView = manager.findViewByPosition(firstPos)!!
    offsetTop = manager.getDecoratedTop(firstView) - manager.getTopDecorationHeight(firstView)
}

// apply changes
adapter.notify...

if (firstPos >= 0) {
    manager.scrollToPositionWithOffset(firstPos, offsetTop)
}

In my case, the view can have a top margin, which also needs to be counted in the offset, otherwise the recyclerview will not scroll to the intended position. To do so, just write:

val topMargin = (firstView.layoutParams as? MarginLayoutParams)?.topMargin ?: 0
offsetTop = manager.getDecoratedTop(firstView) - manager.getTopDecorationHeight(firstView) - topMargin

Even easier if you have ktx dependency in your project:

offsetTop = manager.getDecoratedTop(firstView) - manager.getTopDecorationHeight(firstView) - firstView.marginTop
查看更多
混吃等死
4楼-- · 2020-02-10 06:52

Sadly the workaround presented by yigit scrolls the RecyclerView to the top. This is the best workaround I found till now:

// figure out the position of the first visible item
int firstPos = manager.findFirstCompletelyVisibleItemPosition();
int offsetTop = 0;
if(firstPos >= 0) {
    View firstView = manager.findViewByPosition(firstPos);
    offsetTop = manager.getDecoratedTop(firstView) - manager.getTopDecorationHeight(firstView);
}

// apply changes
adapter.notify...

// reapply the saved position
if(firstPos >= 0) {
    manager.scrollToPositionWithOffset(firstPos, offsetTop);
}
查看更多
登录 后发表回答