Как сделать заголовок раздела (вложенный в другой scrollView) закрепленным в верхней части представления в SwiftUI?

Я хочу, чтобы заголовки прикреплялись к верху при вертикальной прокрутке.

Код примерно такой:

ScrollView([.vertical]) {
    LazyVStack(alignment: .leading, pinnedViews: .sectionHeaders) {
        ForEach(...) {
            ScrollView([.horizontal]) {
                LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
                    Section {
                       ...
                    } header: {
                       ... // <-- the header
                    }
                }
            }
        }
    }
}

Однако, кажется, что in nested scroll views, the pinnedViews property can only pin views in the nearest scroll view.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
187
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Наконец-то разберитесь с проблемой.

Включая некоторые ответы, такие как https://stackoverflow.com/a/71154712/9073579, я в итоге использовал один ScrollView для достижения этой функциональности.

Этот подход также создает проблему, заключающуюся в том, что представление центрируется, когда высоты внутреннего содержимого недостаточно.

Таким образом, мне пришлось потратить дополнительные усилия на решение этого вопроса. Это потребовало дополнительных переменных для поддержания некоторого состояния, таких как ширина всей области прокрутки и расчетная ширина элементов, которые должны быть закреплены.

@State private var width: CGFloat? = nil

var body: some View {
    ScrollViewReader { proxy in
        GeometryReader { geometry in // <-- to get the viewport size
            ScrollView([.vertical, .horizontal]) {
                ZStack(alignment: .topLeading) { // to place the scroll anchor
                    VStack(alignment: .leading) {
                        VStack(alignment: .leading) {
                            // my headers view here
                        }
                        .stickyHorizontal(geometry.size.width, scrollWidth: width)

                        ForEach(0..<2) { i in
                            LazyVStack(alignment: .leading, spacing: 0, pinnedViews: .sectionHeaders) {
                                Section {
                                    ... // body table view
                                } header: {
                                    ... // table header
                                    // calculating the width of header (i.e. the width of table)
                                    .background(GeometryReader { geometry in
                                        Color.clear
                                            .onAppear {
                                                width = geometry.size.width
                                            }
                                            .onChange(of: geometry.size.width) { newValue in
                                                width = newValue
                                            }
                                    })
                                }
                            }
                        }
                      
                        // addtional views (footer)
                                                ...
                      
                        // act as a Spacer(). Stretching the VStack.
                        Color.clear
                            .frame(height: geometry.size.height - 40)
                    }
                    .frame(width: width)

                    // scroll destination
                    Color.clear
                        .frame(width: 1, height: 1)
                        .id("topLeading")
                }
                .onAppear {
                    // make sure the scroll view appears from top leading.
                    proxy.scrollTo("topLeading", anchor: .topLeading)
                }
            }
        }
    }
}

extension View {
    @ViewBuilder
    func stickyHorizontal(_ viewPortWidth: CGFloat, scrollWidth: CGFloat?) -> some View {
        LazyHStack( spacing: 0, pinnedViews: .sectionHeaders) {
            Section {
                Color.clear
                    .frame(width: scrollWidth == nil ? nil : scrollWidth! - viewPortWidth)
            } header: {
                self
                    .frame(width: viewPortWidth)
            }
        }
    }
}

Другие вопросы по теме