RecyclerView 在 ConstraintLayout 中更改其滚动位置

nto*_*rnl 8 android android-recyclerview android-constraintlayout

我遇到了一个问题,RecyclerView当它是ConstraintLayout. 最初,它RecyclerView位于Relative-Frame-LinearLeayouts的视图层次结构深处,并且一切正常,直到我决定使用 ConstraintLayout 扁平化视图树。我注意到每次由于任何原因(窗口调整大小、数据集更改通知等)导致布局更改时, 的滚动位置RecyclerView都会更改。

例如,每次我显示和隐藏软键盘时,内容回收器视图都会漂移一定的像素。

我能够在一个非常简单的布局上重现这种行为:

ConstraintLayout
|---RecyclerView
|---Button
|---EditText
Run Code Online (Sandbox Code Playgroud)

如果我将约束设置RecyclerView为放置在 的任何其他子项之上ConstraintLayout(意味着 RecyclerView 具有底部约束),并且如果我使用LinearLayoutManagerwith reverseLayout = true,我可以重现上述行为。

我应该如何解决这个问题(我不想改变滚动位置)?也许 RecyclerView 和/或 ConstraintLayout 上有一些我不知道的标志......

这是我的layout.xml

ConstraintLayout
|---RecyclerView
|---Button
|---EditText
Run Code Online (Sandbox Code Playgroud)

这里是代码设置RecyclerViewActivity.onCreate()

setContentView(R.layout.activity_main)

val adapter = Adapter()

val layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.VERTICAL
layoutManager.reverseLayout = true

val recycler = findViewById<RecyclerView>(R.id.recycler)
recycler.layoutManager = layoutManager
recycler.adapter = adapter

recycler.addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
    Log.d("TEST", "bottom=$bottom, oldBottom=$oldBottom")
}

recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
        Log.d("TEST", "Scrolled: dx=$dx, dy=$dy")
        Log.d("TEST", "offset = " + recycler.computeVerticalScrollOffset())
    }
})

findViewById<Button>(R.id.button)
        .setOnClickListener {
            adapter.notifyDataSetChanged()
        }
Run Code Online (Sandbox Code Playgroud)

下面是调试日志的片段,这是在多次点击按钮后收集的:

D/TEST: Scrolled: dx=0, dy=0
D/TEST: offset = 4167
D/TEST: bottom=1253, oldBottom=1253
D/TEST: Scrolled: dx=0, dy=0
D/TEST: offset = 3887
D/TEST: bottom=1253, oldBottom=1253
D/TEST: Scrolled: dx=0, dy=0
D/TEST: offset = 3607
D/TEST: bottom=1253, oldBottom=1253
D/TEST: Scrolled: dx=0, dy=0
D/TEST: offset = 3327
D/TEST: bottom=1253, oldBottom=1253
Run Code Online (Sandbox Code Playgroud)

滚动位置正在缓慢变化,内容正在向顶部滚动。偏移量大致等于下方小部件的总高度RecyclerView

只有在满足所有条件时,我才能重现此行为:

  • RecyclerView 位于一个 ConstraintLayout
  • 下面还有其他同级小部件 RecyclerView
  • LinearLayoutManager与任一标志一起使用reverseLayoutstackFromBottom设置为true.

我使用的ConstraintLayout版本是1.1.2.