Quero ter uma grade de botões. Os botões ocuparão o máximo de espaço horizontal disponÃvel e o dividirão uniformemente. Além disso, a altura de todos os botões deve ser a mesma com base no mais alto. De alguma forma, não consigo fazer esses requisitos funcionarem juntos. Aqui, por exemplo, a altura de cada linha é a mesma, mas as alturas entre as linhas são diferentes.
struct ContentView: View {
let texts = [["Short", "A bit longer text", "bbb"],
["a", "A bit longer text", "This is a very long text that might not fit in one line"],
["a", "b", "c"]
]
var body: some View {
VStack {
ForEach(texts, id: \.self) { row in
HStack {
ForEach(row, id: \.self) { text in
Button{ } label: {
Text(text)
.foregroundStyle(.white)
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.red)
.clipShape(Capsule())
}
}
}
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
}
#Preview {
ContentView()
}
Tentei experimentar mais, mas nada funciona e não tenho intuição sobre como fazer a UI progressivamente parecer mais como pretendo que seja. Cada pequena mudança quebra tudo de uma forma grande.

Uma maneira de resolver isso é estabelecer o tamanho do espaço ocupado pelo maior rótulo de texto e, em seguida, mostrar o rótulo de cada botão como uma sobreposição sobre um espaço ocupado (oculto).
A pegada pode ser encontrada usando a
ZStack
com todas as strings em camadas umas sobre as outras. O tamanho doZStack
é determinado pelo tamanho da maior string de texto:Depois disso, você pode usar um
VStack
em combinação com umHStack
para montar a grade, como você estava fazendo antes, ou você pode simplesmente usar umGrid
:Se você não quiser que os botões fiquem tão espalhados, basta remover o
.frame
da ponta.Conforme mencionado nos comentários , você pode escrever um personalizado
Layout
que encontre a linha mais alta e estique as outras linhas até essa altura.Aqui está um exemplo de implementação que usa os espaçamentos padrão das visualizações (veja
LayoutSubview.spacing
). Você pode substituÃ-lo por um espaçamento constante, se desejar.Este código assume que cada linha preencherá todo o espaço disponÃvel horizontalmente e é capaz de se esticar verticalmente para atingir uma determinada altura. Se algumas linhas tiverem um tamanho horizontal fixo, elas serão centralizadas com o restante das linhas. Se você quiser algum outro alinhamento, pode alterar os parâmetros
at:
eanchor:
daview.place
chamada. Por exemplo, para alinhamento inicial, você pode fazer:Exemplo de uso: