Eu estava criando um LazyVerticalGrid simples contendo imagens recuperadas da API pública. Inicialmente, segui um guia que utilizava paginação, mas essa API não possui páginas, então decidi buscar 20 imagens por vez. Cada chamada à API recupera 20 strings, que são inseridas em AsyncImage. Usei o booleano fetchNextImages para buscar as próximas 20 strings e funciona, mas apenas se você não alternar as telas. Tela:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.fortests.components.DuckImage
import com.example.fortests.components.LoadingState
sealed interface DuckViewState {
object Loading : DuckViewState
data class GridDisplay(
val ducks: List<String> = emptyList()
) : DuckViewState
}
@Composable
fun SecondScreen(
viewModel: SecondViewModel = hiltViewModel(),
onDuckClicked: (str: String) -> Unit
) {
LaunchedEffect(key1 = viewModel, block = { viewModel.fetchInitialImages() })
val viewState by viewModel.viewState.collectAsState()
val scrollState = viewModel.scrollState.value
val fetchNextImages: Boolean by remember {
derivedStateOf {
val currentCharacterCount =
(viewState as? DuckViewState.GridDisplay)?.ducks?.size
?: return@derivedStateOf false
val lastDisplayedIndex = scrollState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
?: return@derivedStateOf false
return@derivedStateOf lastDisplayedIndex+1 == currentCharacterCount
}
}
LaunchedEffect(key1 = fetchNextImages, block = {
if (fetchNextImages) viewModel.fetchNextImages()
})
when (val state = viewState) {
DuckViewState.Loading -> LoadingState()
is DuckViewState.GridDisplay -> {
Column {
LazyVerticalGrid(
state = scrollState,
modifier = Modifier.padding(bottom = 90.dp),
contentPadding = PaddingValues(all = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
columns = GridCells.Fixed(2),
content = {
items(
items = state.ducks
) { duck ->
DuckImage(
onClick = { onDuckClicked(duck) },
imageUrl = "https://random-d.uk/api/${duck}.jpg"
)
}
})
}
}
}
}
Modelo de exibição:
import android.app.Application
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.fortests.duckrepo.DuckImagesRepo
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SecondViewModel @Inject constructor(
application: Application, private val duckImagesRepo: DuckImagesRepo
) : ViewModel() {
private val _viewState = MutableStateFlow<DuckViewState>(DuckViewState.Loading)
val viewState: StateFlow<DuckViewState> = _viewState.asStateFlow()
val scrollState = mutableStateOf(LazyGridState())
private val fetchedDucks = mutableListOf<String>()
fun fetchInitialImages() = viewModelScope.launch {
if (fetchedDucks.isNotEmpty()) return@launch
val initialData = duckImagesRepo.fetchImages()
_viewState.update {
return@update DuckViewState.GridDisplay(ducks = initialData)
}
}
fun fetchNextImages() = viewModelScope.launch {
val data = duckImagesRepo.fetchNextData()
_viewState.update { currentState ->
when (currentState) {
is DuckViewState.GridDisplay -> {
val updatedDucks = currentState.ducks + data
DuckViewState.GridDisplay(ducks = updatedDucks)
}
else -> currentState
}
}
}
}
Seria uma boa solução simplesmente salvar todas essas strings em uma lista?