3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

rememberLazyListState の仕組み

Posted at

疑問

次のコードは、表示されている要素のインデックスの中で最も小さいものをログに出力するコードです。出力されるタイミングは値が変わったとき、つまり一方向にゆっくりと 64dp スクロールしたときです。私の環境では 1dp = 2.75px であるため、176px 毎に出力されることになります。

data class Data(val id: Int)
val data = (1..1000).map { Data(it) }

@Composable
fun MainScreen() {
  val state = rememberLazyListState()
  Log.e("TAG", state.firstVisibleItemIndex.toString())

  LazyColumn(Modifier.fillMaxSize(), state = state) {
    items(data, key = { it.id }) {
      Box(Modifier.border(1.dp, Color.Black).fillMaxWidth().height(64.dp))
    }
  }
}

それに対して次のコードは、1px スクロールするたびに出力されます。

data class Data(val id: Int)
val data = (1..1000).map { Data(it) }

@Composable
fun MainScreen() {
  val state = rememberLazyListState()
  // ここだけを書き換えている
  Log.e("TAG", state.firstVisibleItemScrollOffset.toString())
  
  LazyColumn(Modifier.fillMaxSize(), state = state) {
    items(data, key = { it.id }) {
      Box(Modifier.border(1.dp, Color.Black).fillMaxWidth().height(64.dp))
    }
  }
}

私の感覚では、state 変数のプロパティの一部だけを参照していようとも、1px スクロールする毎に firstVisibleItemScrollOffset の値が変わるのだから state 自身が変更されると思ってしまいます。しかし実際はもっと賢くて、firstVisibleItemIndex だけを参照しているときは 176px 毎に再描画が走ってくれます。firstVisibleItemScrollOffset が変更されているにも関わらず。

答え

rememberLazyListState の実装を読むと答えは単純でした。この関数は State#value を返すのではなく、State#value をプロパティに持つ State#value でないオブジェクトを返していました。つまり、state.firstVisibleItemIndexstate.firstVisibleItemScrollOffsetState#value ですが、stateState#value ではありませんでした。

終わりに

参照しているプロパティが変更されたときだけ再描画が行われるので、「スクロールするたびに再描画が走るので rememberLazyListState を使うことは避けよう」と思わなくていいとわかり、安心しました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?