Quero exibir meu conteúdo como está, centralizado verticalmente, se ele couber na altura da tela.
Só quero envolvê-lo ScrollView
se sua altura exceder a altura da tela.
Estou evitando colocá-lo em um ScrollView
por padrão, porque conseguir centralização vertical dentro de um ScrollView
pode ser complicado.
Eu tento usar ViewThatFits
com ScrollView
.
Eu uso o seguinte código para mostrar conteúdo de altura pequena.
Nenhum ScrollView é renderizado (comportamento correto)
import SwiftUI
struct ContentView: View {
var largeContent: some View {
VStack {
Spacer()
ForEach(1...20, id: \.self) { i in
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(i). Large content!")
.font(.largeTitle)
}
Spacer()
}
}
var smallContent: some View {
VStack {
Spacer()
ForEach(1...2, id: \.self) { i in
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(i). Small content!")
.font(.largeTitle)
}
Spacer()
}
}
var body: some View {
VStack {
let smallContent = smallContent
// The top portion dedicated to content
GeometryReader { x in
ViewThatFits {
// Option 1: Content fits without scrolling.
smallContent
.background(Color.yellow)
.frame(maxHeight: x.size.height)
.frame(maxWidth: .infinity)
// Option 2: Content is too tall, so wrap it in a ScrollView.
ScrollView {
smallContent
.background(Color.red)
.frame(minHeight: x.size.height)
.frame(maxWidth: .infinity)
}
}
}
Text("Button")
.background(Color.blue)
.font(.largeTitle)
}
}
}
Está dentro da minha expectativa porque
- Não
ScrollView
é renderizado. - O conteúdo é centralizado verticalmente.
Nenhum ScrollView é renderizado (comportamento errado)
import SwiftUI
struct ContentView: View {
var largeContent: some View {
VStack {
Spacer()
ForEach(1...20, id: \.self) { i in
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(i). Large content!")
.font(.largeTitle)
}
Spacer()
}
}
var smallContent: some View {
VStack {
Spacer()
ForEach(1...2, id: \.self) { i in
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(i). Small content!")
.font(.largeTitle)
}
Spacer()
}
}
var body: some View {
VStack {
let largeContent = largeContent
// The top portion dedicated to content
GeometryReader { x in
ViewThatFits {
// Option 1: Content fits without scrolling.
largeContent
.background(Color.yellow)
.frame(maxHeight: x.size.height)
.frame(maxWidth: .infinity)
// Option 2: Content is too tall, so wrap it in a ScrollView.
ScrollView {
largeContent
.background(Color.red)
.frame(minHeight: x.size.height)
.frame(maxWidth: .infinity)
}
}
}
Text("Button")
.background(Color.blue)
.font(.largeTitle)
}
}
}
#Preview {
ContentView()
}
Agora, alterei para exibir "conteúdo grande". Esperava que a cor vermelha ScrollView
fosse renderizada. No entanto, não foi.
Posso saber o que há de errado com meu código? Obrigado.
A razão pela qual a versão amarela é mostrada quando
largeContent
é mostrada é porque você está impondo uma altura máxima igual àGeometryReader
altura. Isso se encaixa! Então esta é a vista mostrada.O que acontece então é que a visualização transborda.
Você pode ver melhor as consequências se alterar a ordem dos modificadores, como
.background
segue.frame
. Então tente aplicar.clipped
:Se você substituir
x.size.height
por.infinity
, para que ele possa usar toda a altura que realmente precisa, funcionará como você espera: