【问题标题】:Screen scrolls to the top (Jetpack Compose Pagination)屏幕滚动到顶部(Jetpack Compose 分页)
【发布时间】:2021-12-31 18:17:46
【问题描述】:

我正在尝试在我的应用程序中进行分页。首先,我从 Api(限制)获取 20 个项目,每次我向下滚动到屏幕底部时,它都会将此数字增加 20(nextPage())。但是,当调用此函数时,屏幕会转到顶部,但我希望它从中断的地方继续。我该怎么做?

这是我的代码:

CharacterListScreen:

@Composable
fun CharacterListScreen(
    characterListViewModel: CharacterListViewModel = hiltViewModel()
) {

    val state = characterListViewModel.state.value
    val limit = characterListViewModel.limit.value

    Box(modifier = Modifier.fillMaxSize()) {
        val listState = rememberLazyListState()

        LazyColumn(modifier = Modifier.fillMaxSize(), state = listState) {
            itemsIndexed(state.characters) { index, character ->
                characterListViewModel.onChangeRecipeScrollPosition(index)
                if ((index + 1) >= limit) {
                    characterListViewModel.nextPage()
                }
                CharacterListItem(character = character)
            }
        }

        if (state.error.isNotBlank()) {
            Text(
                text = state.error,
                color = MaterialTheme.colors.error,
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 20.dp)
                    .align(Alignment.Center)
            )
        }
        if (state.isLoading) {
            CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
        }
    }
}

CharacterListViewModel:

@HiltViewModel
class CharacterListViewModel @Inject constructor(
    private val characterRepository: CharacterRepository
) : ViewModel() {

    val state = mutableStateOf(CharacterListState())
    val limit = mutableStateOf(20)
    var recipeListScrollPosition = 0

    init {
        getCharacters(limit.value, Constants.HEADER)
    }

    private fun getCharacters(limit : Int, header : String) {
        characterRepository.getCharacters(limit, header).onEach { result ->
            when(result) {
                is Resource.Success -> {
                    state.value = CharacterListState(characters = result.data ?: emptyList())
                }
                is Resource.Error -> {
                    state.value = CharacterListState(error = result.message ?: "Unexpected Error")
                }
                is Resource.Loading -> {
                    state.value = CharacterListState(isLoading = true)
                }
            }
        }.launchIn(viewModelScope)
    }

    private fun incrementLimit() {
        limit.value = limit.value + 20
    }

    fun onChangeRecipeScrollPosition(position: Int){
        recipeListScrollPosition = position
    }

    fun nextPage() {
            if((recipeListScrollPosition + 1) >= limit.value) {
                incrementLimit()
                characterRepository.getCharacters(limit.value, Constants.HEADER).onEach {result ->
                    when(result) {
                        is Resource.Success -> {
                            state.value = CharacterListState(characters = result.data ?: emptyList())
                        }
                        is Resource.Error -> {
                            state.value = CharacterListState(error = result.message ?: "Unexpected Error")
                        }
                        is Resource.Loading -> {
                            state.value = CharacterListState(isLoading = true)
                        }
                    }
                }.launchIn(viewModelScope)
            }
    }

}

CharacterListState:

data class CharacterListState(
    val isLoading : Boolean = false,
    var characters : List<Character> = emptyList(),
    val error : String = ""
)

【问题讨论】:

  • 我真的不确定你想用这部分实现什么:characterListViewModel.onChangeRecipeScrollPosition(index) if ((index + 1) &gt;= limit) { characterListViewModel.nextPage() }
  • 您没有使用Paging3库的任何特殊原因?

标签: android kotlin pagination retrofit android-jetpack-compose


【解决方案1】:

不确定您是否正确使用了 LazyListState。在您的视图模型中,创建一个 LazyListState 实例:

val lazyListState: LazyListState = LazyListState()

将其传递到您的可组合中并按如下方式使用它:

@Composable
fun CharacterListScreen(
    characterListViewModel: CharacterListViewModel = hiltViewModel()
) {

    val limit = characterListViewModel.limit.value

    Box(modifier = Modifier.fillMaxSize()) {
        
        LazyColumn(modifier = Modifier.fillMaxSize(), state = characterListViewModel.lazyListState) {
            itemsIndexed(state.characters) { index, character ->

            }
        }
    }
}

【讨论】:

  • 感谢您的回答,但没有成功。
  • 我误解了你的问题。我更新了我的解决方案。这就是我保持列表状态并在添加其他项目时保持最后滚动位置的方式。或者,您也可以使用 rememberLazyListState。另一件事 - 您不需要跟踪限制来确定何时加载更多数据。这是内置在 Paging api 中的。您设置分页大小,当用户滚动到底部时会自动加载更多数据。
【解决方案2】:

我认为这里的问题是您在加载时创建了CharacterListState(isLoading = true)。这将创建一个具有空元素列表的对象。所以 compose 在这里渲染一个空的LazyColumn 来重置滚动状态。简单的解决方案可能是state.value = state.value.copy(isLoading = true)。然后,在加载时,可以保留项目列表(滚动状态也是如此)

【讨论】:

  • 是的,效果非常好。我明白了这个问题,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2010-11-16
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多