每当 LazyVerticalStaggeredGrid/LazyColumn 到达末尾/最后一项时,我都会实现分页或加载更多数据。一切都按预期工作,但是,当数据加载更多功能时,LazyVerticalStaggeredGrid 会关闭屏幕并仅显示加载程序,一旦加载更多数据,LazyVerticalStaggeredGrid 就会再次显示。我不确定我在这里做错了什么。为了更好地理解,我附上了下面的代码。
Column {
val dataFlow = viewModel.uiStateFlow.collectAsStateWithLifecycle()
if (dataFlow.value.error is Throwable) {
Log.d(TAG, "View: Error")
Toast.makeText(
LocalContext.current,
dataFlow.value.error.toString(),
Toast.LENGTH_LONG
).show()
} else {
Log.d(TAG, "View: listview")
PhotosGrid(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
list = dataFlow.value.list,
loading = dataFlow.value.loading
) {
viewModel.getPhotos()
}
}
}
@Composable
fun PhotosGrid(
modifier: Modifier,
lazyListState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
list: List<PhotosModel>,
loading: Boolean = false,
loadMore: () -> Unit
) {
val reachedBottom: Boolean by remember { derivedStateOf { lazyListState.reachedBottom() } }
if (reachedBottom && !loading) {
Log.d(TAG, "View: reached bottom")
loadMore()
}
LazyVerticalStaggeredGrid(
modifier = modifier,
columns = StaggeredGridCells.Fixed(2),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalItemSpacing = 4.dp,
contentPadding = PaddingValues(all = 4.dp),
state = lazyListState
) {
items(list) {
PhotosItem(photosModel = it)
}
if (loading) {
item {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary
)
}
}
}
}
@Composable
fun PhotosItem(photosModel: PhotosModel) {
val imgUrl = photosModel.urls?.regular
Box {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(imgUrl)
.crossfade(true)
.build(),
error = painterResource(R.drawable.broken_image),
placeholder = painterResource(R.drawable.ic_loader),
contentDescription = photosModel.description,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.clip(RectangleShape)
)
}
}
internal fun LazyStaggeredGridState.reachedBottom(buffer: Int = 1): Boolean {
val lastVisibleItem = this.layoutInfo.visibleItemsInfo.lastOrNull()
return lastVisibleItem?.index != 0 && lastVisibleItem?.index == this.layoutInfo.totalItemsCount - buffer
}
ViewModel 中的逻辑
var pageNo = 0
private val _uiStateFlow = MutableStateFlow(UiState(false, emptyList(), null))
val uiStateFlow: StateFlow<UiState> = _uiStateFlow
init {
viewModelScope.launch {
photosRepository.getAllPhotos().collectLatest { list ->
if (list.isEmpty()) {
getPhotos()
} else {
_uiStateFlow.update { UiState(list = list) }
}
}
}
}
fun getPhotos() = viewModelScope.launch {
photosRepository.getPhotos(accessKey = ConstantUrls.ACCESS_KEY, pageNo = pageNo++) { event ->
when(event) {
is ResponseEvent.Failure -> {
_uiStateFlow.update { UiState(error = event.error) }
}
ResponseEvent.Loading -> {
_uiStateFlow.update { UiState(loading = true) }
}
}
}
}
data class UiState(
val loading: Boolean = false,
val list: List<PhotosModel> = emptyList(),
val error: Throwable? = null
)
如果您像这样发送加载
UIState
_uiStateFlow.update { UiState(loading = true) }
如果不传递
list
属性的值,它将默认使用您在 emptyList
类中指定的 UIState
:
val list: List<PhotosModel> = emptyList()
因此,在加载时,
LazyVerticalStaggeredGrid
变为空,仅显示单个加载项。 UIState
一起传递,如下所示:
_uiStateFlow.update { UiState(loading = true, list = uiStateFlow.value) }