还记得惰性列中的滚动位置吗?

Kha*_*yar 12 android kotlin android-jetpack-compose

我知道记住惰性列表状态并且它工作正常

 setContent {       
       Test(myList) // Call Test with a dummy list
    }

  @Composable
    fun Test(data: List<Int>){
        val state = rememberLazyListState()

        LazyColumn(state = state) {
            items(data){ item ->Text("$item")}
          }
     }
Run Code Online (Sandbox Code Playgroud)

它会记住滚动位置,每次旋转和更改配置后它都会是相同的
但是每当我尝试从数据库捕获数据并使用像collectAsState这样的方法时
它不起作用,这似乎是一个问题

   setContent{
      val myList by viewModel.getList.collectAsState(initial = listOf())
      Test(myList)
   }
Run Code Online (Sandbox Code Playgroud)

Mat*_*tti 7

永远保存 LazyListState

/**
 * Static field, contains all scroll values
 */
private val SaveMap = mutableMapOf<String, KeyParams>()

private data class KeyParams(
    val params: String = "",
    val index: Int,
    val scrollOffset: Int
)

/**
 * Save scroll state on all time.
 * @param key value for comparing screen
 * @param params arguments for find different between equals screen
 * @param initialFirstVisibleItemIndex see [LazyListState.firstVisibleItemIndex]
 * @param initialFirstVisibleItemScrollOffset see [LazyListState.firstVisibleItemScrollOffset]
 */
@Composable
fun rememberForeverLazyListState(
    key: String,
    params: String = "",
    initialFirstVisibleItemIndex: Int = 0,
    initialFirstVisibleItemScrollOffset: Int = 0
): LazyListState {
    val scrollState = rememberSaveable(saver = LazyListState.Saver) {
        var savedValue = SaveMap[key]
        if (savedValue?.params != params) savedValue = null
        val savedIndex = savedValue?.index ?: initialFirstVisibleItemIndex
        val savedOffset = savedValue?.scrollOffset ?: initialFirstVisibleItemScrollOffset
        LazyListState(
            savedIndex,
            savedOffset
        )
    }
    DisposableEffect(Unit) {
        onDispose {
            val lastIndex = scrollState.firstVisibleItemIndex
            val lastOffset = scrollState.firstVisibleItemScrollOffset
            SaveMap[key] = KeyParams(params, lastIndex, lastOffset)
        }
    }
    return scrollState
}
Run Code Online (Sandbox Code Playgroud)

用法:

LazyColumn(
    state = rememberForeverLazyListState(key = "Overview")
)
Run Code Online (Sandbox Code Playgroud)

点击此处查看原始答案

永久保存 ScrollState

从之前的答案中汲取灵感,我创建了一个类似的remember方法来保存ScrollState.

import androidx.compose.foundation.ScrollState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.saveable.rememberSaveable

/**
 * Static field, contains all scroll values
 */
private val SaveMap = mutableMapOf<String, ScrollKeyParams>()

private data class ScrollKeyParams(
  val value: Int
)

/**
 * Save scroll state on all time.
 * @param key value for comparing screen
 * @param initial see [ScrollState.value]
 */
@Composable
fun rememberForeverScrollState(
  key: String,
  initial: Int = 0
): ScrollState {
  val scrollState = rememberSaveable(saver = ScrollState.Saver) {
    val scrollValue: Int = SaveMap[key]?.value ?: initial
    SaveMap[key] = ScrollKeyParams(scrollValue)
    return@rememberSaveable ScrollState(scrollValue)
  }
  DisposableEffect(Unit) {
    onDispose {
      SaveMap[key] = ScrollKeyParams(scrollState.value)
    }
  }
  return scrollState
}
Run Code Online (Sandbox Code Playgroud)

用途:

val scrollState = rememberForeverScrollState("history_screen")
  
Column(
  modifier = modifier
    .fillMaxSize()
    .verticalScroll(scrollState)
) {
 ...
}
Run Code Online (Sandbox Code Playgroud)

旧答案

不幸的是,目前还没有一种本地方法可以做到这一点,但您可以使用以下代码:

val listState = rememberLazyListState()
Run Code Online (Sandbox Code Playgroud)

listState有3种方法:

  • firstVisibleItemIndex
  • firstVisibleItemScrollOffset
  • isScrollInProgress

所有这些都是State()为了让您始终能够获取更新的数据。例如,如果您开始滚动列表,isScrollInProgress将从 更改falsetrue

保存和恢复状态

val listState: LazyListState = rememberLazyListState(viewModel.index, viewModel.offset)

  LaunchedEffect(key1 = listState.isScrollInProgress) {
    if (!listState.isScrollInProgress) {
      viewModel.index = listState.firstVisibleItemIndex
      viewModel.offset = listState.firstVisibleItemScrollOffset
    }
  }
Run Code Online (Sandbox Code Playgroud)