Aqui está um exemplo de código completo de uma tentativa de visualização de cabeçalho duplo fixo:
struct ContentView: View {
var body: some View {
ScrollView(showsIndicators: false) {
LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
Section {
SecondView()
} header: {
HeaderView()
}
}
}
}
}
struct HeaderView: View {
var body: some View {
Rectangle()
.fill(.green)
.frame(height: 50)
}
}
struct SecondView: View {
var body: some View {
LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
Section {
VStack {
ForEach(0..<20) { index in
ItemView(index: index)
}
}
} header: {
SecondHeaderView()
}
}
}
}
struct SecondHeaderView: View {
var body: some View {
Rectangle()
.fill(.red)
.frame(height: 60)
}
}
struct ItemView: View {
let index: Int
var body: some View {
VStack {
Text("Item \(index)")
.padding()
}
.frame(height: 80)
.background(.gray)
}
}
#Preview {
ContentView()
}
Note que inicialmente, o vermelho SecondHeaderView
está corretamente posicionado abaixo do verde HeaderView
. No entanto, ao rolar, o cabeçalho vermelho rola abaixo do cabeçalho verde até que fique na mesma posição y que o cabeçalho verde.
Preciso que o cabeçalho vermelho fique ancorado abaixo do cabeçalho verde. Note que ele SecondView
pode não estar sempre incorporado em um ContentView
. Ele poderia viver sozinho e ainda precisar de seu próprio cabeçalho fixo para funcionar, então acho que ambas as visualizações precisam do LazyVStack
.
Eu mexi em vários deslocamentos de visualização do GeometryReader, tentando posicionar o cabeçalho vermelho corretamente, mas não consegui.
Aqui estão duas maneiras possíveis de resolver
1. Combine os cabeçalhos juntos
Uma maneira fácil de resolver é combinar os dois cabeçalhos juntos. Se for possível que eles
SecondView
sejam mostrados isoladamente, você pode passar um sinalizador para indicar se o cabeçalho deve ser mostrado ou não:Para mostrar
SecondView
isoladamente:2. Aplique preenchimento ao segundo cabeçalho
Alternativamente, se for possível assumir que o segundo cabeçalho estará na posição correta quando inicialmente mostrado, então essa posição pode ser medida em
.onAppear
. Então, para mantê-lo na mesma posição, o preenchimento superior pode ser aplicado para compensar qualquer movimento de rolagem.O mesmo preenchimento deve ser aplicado como preenchimento superior negativo ao conteúdo rolado, caso contrário, o conteúdo não se moverá até que o movimento de arrastar atinja a altura do primeiro cabeçalho.
Descobri que o cabeçalho estava fazendo pequenos movimentos quando a rolagem estava acontecendo, o que estava causando erros no console sobre "ação tentou atualizar várias vezes por quadro". Esses erros podem ser prevenidos verificando se o ajuste difere do valor anterior por um valor limite, 0,1 funciona bem.
Com essa abordagem,
SecondView
pode ser mostrado isoladamente sem precisar passar um sinalizador.Se não for possível assumir que o segundo cabeçalho estará na posição correta no show inicial, então a altura do cabeçalho pai pode ser passada como um parâmetro. Esta é talvez uma maneira mais segura de resolver ao usar a abordagem de preenchimento:
Ambas as abordagens funcionam da mesma forma. É assim que parece para o caso do cabeçalho duplo: