Ask Your Question
1

What's the method for keeping a section header (included in another scrollView) fixed at the top of the SwiftUI view?

asked 2023-05-22 14:49:11 +0000

woof gravatar image

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2023-05-22 14:54:02 +0000

lalupa gravatar image

To keep a section header fixed at the top of a SwiftUI view, you can use the following steps:

  1. Create a parent scrollView that will contain the section header and the child scrollView.

  2. Inside the parent scrollView, add the section header as the first item, followed by the child scrollView.

  3. Apply a fixed height to the section header, which will determine its size and position.

  4. Add a GeometryReader to the parent scrollView to capture its dimensions.

  5. Create a State variable to store the parent scrollView offset.

  6. Add a .onPreferenceChange modifier to the child scrollView that sends its offset to the parent scrollView through a PreferenceKey.

  7. Use the parent scrollView offset to adjust the position of the section header.

Here's an example implementation:

struct ContentView: View {
    @State private var parentScrollViewOffset: CGFloat = 0

    var body: some View {
        ScrollView {
            GeometryReader { geometry in
                VStack {
                    SectionHeader()
                        .frame(height: 50)
                        .offset(y: max(-geometry.safeAreaInsets.top, -parentScrollViewOffset))

                    ChildScrollView()
                        .background(GeometryReader {
                            Color.clear.preference(key: OffsetPreferenceKey.self, 
                                                   value: $0.frame(in: .global).minY)
                        })
                        .onPreferenceChange(OffsetPreferenceKey.self) { offset in
                            parentScrollViewOffset = offset
                        }
                }
            }
        }
    }
}

struct SectionHeader: View {
    var body: some View {
        Text("Header")
            .foregroundColor(.white)
            .frame(maxWidth: .infinity)
            .background(Color.blue)
    }
}

struct ChildScrollView: View {
    var body: some View {
        ScrollView {
            ForEach(1..<100) { index in
                Text("Item \(index)")
                    .frame(height: 50)
                    .background(Color.gray.opacity(0.2))
            }
        }
    }
}

// Preference key to capture the child scrollView offset
struct OffsetPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0

    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account. This space is reserved only for answers. If you would like to engage in a discussion, please instead post a comment under the question or an answer that you would like to discuss

Add Answer


Question Tools

Stats

Asked: 2023-05-22 14:49:11 +0000

Seen: 12 times

Last updated: May 22 '23