#android #kotlin #pagination #retrofit #android-jetpack-compose
Вопрос:
Я пытаюсь выполнить разбиение на страницы в своем приложении. Во-первых, я выбираю 20 элементов из Api (ограничение), и каждый раз, когда я прокручиваю вниз до нижней части экрана, это число увеличивается на 20 ( nextPage()
). Однако, когда вызывается эта функция, экран переходит наверх, но я хочу, чтобы он продолжался с того места, на котором остановился. Как я могу это сделать?
Вот мой код:
Экран списка персонажей:
@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 -gt; characterListViewModel.onChangeRecipeScrollPosition(index) if ((index 1) gt;= 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)) } } }
Characterlistviewмодель:
@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 -gt; when(result) { is Resource.Success -gt; { state.value = CharacterListState(characters = result.data ?: emptyList()) } is Resource.Error -gt; { state.value = CharacterListState(error = result.message ?: "Unexpected Error") } is Resource.Loading -gt; { 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) gt;= limit.value) { incrementLimit() characterRepository.getCharacters(limit.value, Constants.HEADER).onEach {result -gt; when(result) { is Resource.Success -gt; { state.value = CharacterListState(characters = result.data ?: emptyList()) } is Resource.Error -gt; { state.value = CharacterListState(error = result.message ?: "Unexpected Error") } is Resource.Loading -gt; { state.value = CharacterListState(isLoading = true) } } }.launchIn(viewModelScope) } } }
Состояние списка персонажей:
data class CharacterListState( val isLoading : Boolean = false, var characters : Listlt;Charactergt; = emptyList(), val error : String = "" )
Комментарии:
1. Я действительно не уверен, чего вы пытаетесь достичь с помощью этой части:
characterListViewModel.onChangeRecipeScrollPosition(index) if ((index 1) gt;= limit) { characterListViewModel.nextPage() }
2. По какой-то конкретной причине вы не используете
Paging3
библиотеку?
Ответ №1:
Я думаю, что проблема здесь в том, что вы создаете CharacterListState(isLoading = true)
во время загрузки. Это создает объект с пустым списком элементов. Поэтому compose отображает LazyColumn
здесь пустое поле, которое сбрасывает состояние прокрутки. Простым решением для этого может быть state.value = state.value.copy(isLoading = true)
. Затем, во время загрузки, список элементов может быть сохранен (как и состояние прокрутки).
Комментарии:
1. Да, это сработало действительно здорово. Я понял проблему, большое вам спасибо.
Ответ №2:
Не уверен, правильно ли вы используете состояние LazyList. В вашей модели представления создайте экземпляр 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 -gt; } } } }
Комментарии:
1. Спасибо за ответ, но это не сработало.
2. Я неправильно понял ваш вопрос. Я обновил свое решение. Вот как я сохраняю состояние списка, и он сохраняет последнюю позицию прокрутки при добавлении дополнительных элементов. В качестве альтернативы вы также можете использовать rememberLazyListState. Другое дело — вам не нужно отслеживать ограничения, чтобы определить, когда загружать больше данных. Это встроено в api подкачки. Вы задаете размер подкачки, и дополнительные данные будут автоматически загружаться, когда пользователь прокручивает страницу вниз.