Estou tentando criar uma UI que se parece muito com a que está no topo da página do Material3 Chip .
Parece que a melhor maneira de fazer isso é construir um LazyVerticalStaggeredGrid
, cujo conteúdo consiste em FilteredChip
composables.
Um único FilteredChip em uma coluna é exibido perfeitamente. Mas quando eu o envolvo em um LazyVerticalStaggeredGrid, ele ignora as restrições de tamanho do texto e reduz a largura de cada chip, e fornece uma altura muito grande. De acordo com o Layout Inspector, o texto tem largura de 0 dp e altura de 140 dp. Além disso, ele ignora meu esquema de cores de tema.
Eu esperava que ele medisse o tamanho do texto dentro do Text composable e passasse isso para determinar a largura de cada chip e a altura de cada linha. Se não é assim que LazyGrids funcionam, como devo abordar isso?
Aqui está um exemplo muito simples que ilustra meu problema:
@Composable
fun VerticalGrid(
contentList: List<String>,
modifier: Modifier = Modifier,
) {
LazyVerticalStaggeredGrid(
horizontalArrangement = Arrangement.spacedBy(16.dp),
columns = StaggeredGridCells.Adaptive(minSize = 4.dp),
verticalItemSpacing = 8.dp,
modifier = modifier.fillMaxSize()
) {
var selected = false
items(contentList) { text ->
Chip(text, selected, { selected = !selected }, modifier)
}
}
}
@Composable
fun Chip(
text: String,
selected: Boolean,
onClick: () -> (Unit),
modifier: Modifier = Modifier,
) {
FilterChip(
onClick = onClick,
label = { Text(text = text) },
selected = selected,
modifier = modifier
)
}
object Content {
val contentList = mutableListOf<String>()
init {
for (i in 10..50) {
contentList.add("Label$i")
}
}
}
@Preview(showBackground = true)
@Composable
fun ChipPreview1() {
StaggeredGridOfChipsTheme {
Column(
verticalArrangement = Arrangement.Top,
modifier = Modifier.fillMaxSize()
) {
Chip("Hello", true, {})
}
}
}
@Preview(showBackground = true)
@Composable
fun VerticalGridPreview1() {
StaggeredGridOfChipsTheme {
VerticalGrid(Content.contentList, Modifier.fillMaxSize())
}
}
Isso resulta no seguinte comportamento:
Qualquer dica que pudesse me ajudar a solucionar esse problema também seria bem-vinda.
Você restringe o tamanho de cada coluna no
LazyVerticalStaggeredGrid
usandoStaggeredGridCells.Adaptive(minSize = 4.dp)
. Da documentação:Isso significa que as colunas são apenas
4.dp
largas (+ algum espaço marginal extra). Tente defini-lo para80.dp
para ver a diferença.Se seus chips não forem todos do mesmo tamanho, uma grade não é a melhor escolha, você deve usar uma FlowRow:
Vamos dar uma olhada mais de perto no que
LazyVerticalStaggeredGrid
realmente é:LazyVertical StaggeredGrid: O comportamento vertical preguiçoso é comparável ao de um
LazyColumn
. Isso significa que você não tem limitação vertical, você pode rolar infinitamente (desde que haja elementos disponíveis para exibir, é claro).LazyVerticalStaggered Grid : Uma grade consiste em linhas e colunas onde todas as células têm o mesmo tamanho. Elas não precisam ser quadradas (ou seja, largura==altura), mas cada célula tem a mesma largura que todas as outras células. O mesmo se aplica à altura. Um rgid é como um raster.
LazyVertical Staggered Grid: Uma grade escalonada , por outro lado, pode ter células de tamanho variável. Obviamente, as células não podem ter um tamanho arbitrário, caso contrário, haveria muito espaço vazio e não utilizado. O escalonamento se relaciona ao tamanho variável na direção de rolagem , somente isso é variável. Em uma grade escalonada de rolagem vertical, essa é a altura .
Veja este exemplo dos documentos :
Ele tem três colunas de largura igual que podem ser roladas verticalmente. Cada célula tem a mesma largura, mas uma altura variável . É assim que um
LazyVerticalStaggeredGrid
normalmente se parece.Essa imagem é do segundo exemplo do link acima. Ela define explicitamente o número de colunas para três usando
StaggeredGridCells.Fixed(3)
. A largura real das colunas depende da largura geral disponível, cada coluna recebe um terço dela. Quando o dispositivo é girado para o modo paisagem, ainda serão três colunas, cada uma com uma largura muito maior.O primeiro exemplo , no entanto, usa
StaggeredGridCells.Adaptive(200.dp)
, semelhante ao que você usou no seu código. Isso significa que o número de colunas é flexível e se ajusta ao espaço disponível. A única restrição é que cada coluna deve ter pelo menos200.dp
largura. Então, vamos supor que a largura geral disponível para o LazyVerticalStaggeredGrid seja 500.dp. Isso significa que apenas duas colunas com pelo menos200.dp
podem caber. As restantes100.dp
são distribuídas uniformemente para as outras colunas, então cada uma é250.dp
larga. Quando o dispositivo é girado para o modo paisagem e agora há1000.dp
disponível, então você teria cinco colunas, cada uma exatamente200.dp
larga. É por isso que é chamado deAdaptive
: O número de colunas se adapta ao espaço disponível.Agora, quando o conteúdo real de cada célula é exibido (imagens nesses exemplos, Chips no seu código), o conteúdo é redimensionado para caber. É assim que os componentes de layout do Compose funcionam em geral, não é específico para LazyVerticalStaggeredGrid. No seu código, as colunas são apenas
4.dp
largas (mais uma fração insignificante do espaço restante), então os Chips são solicitados a se redimensionarem de acordo. Eles fazem o melhor que podem, envolvendo cada letra em uma nova linha para que a largura fique a menor possível enquanto cresce em altura. Isso é possível porque a altura não é restrita (veja o ponto 3 acima, a grade é verticalmente escalonada .)Não relacionado, mas ainda assim digno de nota:
Você deve passar o
modifier
parâmetro deVerticalGrid
somente para o primeiro elemento (LazyVerticalStaggeredGrid
), não para outros elementos (oChips
). Caso contrário, ele bagunçará a semântica do modificador e se tornará imprevisível para o chamador.Em
VerticalGrid
você declara a variávelselected
como um Boolean simples. Precisa ser umMutableState<Boolean>
though se você quiser que seus Chips sejam atualizados adequadamente. Além disso, essa variável precisa ser movida dentro doitems
loop para que cada chip tenha seu próprio State, caso contrário, alternar um chip alternará todos os outros também. Compare com como eu fiz acima no exemplo FlowRow.Você pode criar seus dados de teste
Content.contentList
muito mais facilmente. Se quiser uma lista de 41 rótulos diferentes, você pode simplesmente usar isto:Se você quiser que seja de 10 a 50 inclusive, você pode usar isto: