Home > Net >  SwiftUI - LazyVStack pinnedViews in another
SwiftUI - LazyVStack pinnedViews in another

Time:07-19

How to create something like this

LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) {
    Section(header: Text("foo") ) {
        LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) {
            Section (header: Text("bar") ) {
                Text("1")
                Text("2")
                ...
            }
            Section (header: Text("baz") ) {
                Text("1")
                Text("2")
                ...
            }
        }
    }
}

I need two fixed header but in this solution headers colide when fixed position

Thanks

CodePudding user response:

You can give the sub headers a background (in white / bg color), and also have to push the first header back using zIndex.

enter image description here

struct ContentView: View {
    var body: some View {
        ScrollView {
            LazyVStack(alignment: .leading, pinnedViews: [.sectionHeaders]) {

                Section(header:
                    Text("Overall Header")
                    .zIndex(-1) // zIndex here
                ) {
                    
                    LazyVStack(alignment: .leading, pinnedViews: [.sectionHeaders]) {
                        
                        Section (header:
                                    Text("Header One")
                            // give background here
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .background(.gray)
                        ) {
                            ForEach(0..<30) { item in
                                Text("Item \(item)")
                            }
                        }

                        Section (header:
                                    Text("Header Two")
                                 // give background here
                                 .frame(maxWidth: .infinity, alignment: .leading)
                                 .background(.gray)
                        ) {
                            ForEach(0..<50) { item in
                                Text("Item \(item)")
                            }
                        }
                    }
                }
            }
        }
        .font(.title2)
        .padding()
    }
}

CodePudding user response:

Here is some hack :)
It' using the package "SwiftUITrackableScrollView" to be found here: "https://github.com/maxnatchanon/trackable-scroll-view".
But there are several solutions for a trackable scrollview you can find, or implement one by yourself.

It works fine, the only problem is to get/define the relevant positions of headers. Its easy if you have a predefined/fixed item height.

enter image description here

import SwiftUI
import SwiftUITrackableScrollView


struct MyHeaders: Identifiable {
    let id = UUID()
    let title: String
    let position: CGFloat
    var active: Bool = false
}


struct ContentView: View {
    
    @State private var offset = CGFloat.zero // Content offset available to use

    @State private var myHeaders = [
        MyHeaders(title: "Outer Header One", position: 0),
        MyHeaders(title: "Inner Header One", position: 0),
        MyHeaders(title: "Inner Header Three", position: 264),
        MyHeaders(title: "Outer Header Two", position: 525),
        MyHeaders(title: "Inner Header Three", position: 525),
    ]

    var body: some View {
        
        TrackableScrollView(.vertical, showIndicators: false, contentOffset: $offset) {
            LazyVStack(alignment: .leading) {
                
                Text("Outer Header One")

                Text("Inner Header One")
                ForEach(0..<10) { item in
                    Text("Item \(item)")
                }
                Text("Inner Header Two")
                ForEach(0..<10) { item in
                    Text("Item \(item)")
                }

                Text("Outer Header Two")

                Text("Inner Header Three")
                ForEach(0..<30) { item in
                    Text("Item \(item)")
                }
                
            }
        }
        .onChange(of: offset) { newValue in
            print(offset)
            for i in 0..<myHeaders.count {
                myHeaders[i].active = myHeaders[i].position < offset
            }
        }
        .overlay(
            VStack(alignment: .leading) {
                ForEach(myHeaders) { header in
                    if header.active {
                        Text(header.title)
                    }
                }
            }
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(.orange)
                .background(.background)
            , alignment: .topLeading
        )
        .font(.title2)
        .padding()
    }
}
  • Related