1

I'm trying recreate a view in SwiftUI that has the same behaviour as the Twitter profile page.

The expected behaviour is a stretchy header, with tabbed views underneath.

The content size of each tab will differ, however when changing tab the view should maintain the scroll position. It should not jump and resize.

I have embedded a TabView within a ScrollView and have something close to what I am expected, however my TabView does not size itself to its content and I must give it a fixed value.

This has the side effect of cutting off content in the longer tab.

Is it possible to achieve this effect?


struct ContentView: View {
    
    @State private var selection: Int = 0
    
    var body: some View {
        GeometryReader { proxy in
            ScrollView {
                VStack(spacing: 0) {
                    ProfileHeaderView()
                        .frame(height: 184)
                    TabBarView(selection: $selection)
                        .frame(height: 44)
                        .background(Color.purple)
                }
             
                TabView(selection: $selection) {
                    LazyVStack {
                        Text("Tab #1 - Row #0")
                    }
                    .tag(0)
                    
                    LazyVStack {
                        ForEach(0..<50) { index in
                            Text("Tab #2 - Row #\(index)")
                        }
                    }
                    .tag(1)
                }
                .frame(minHeight: proxy.frame(in: .global).height - 228)
            }
        }
    }
}

struct ProfileHeaderView: View {
        
    var body: some View {
        GeometryReader { proxy in
            let minY = proxy.frame(in: .global).minY
            let height = proxy.frame(in: .global).height
            Color.red
                .offset(y: minY > 0 ? -minY : 0)
                .frame(height: minY > 0 ? height + minY : height)
        }
    }
}

struct TabBarView: View {
    
    @Binding var selection: Int
    @State var index: Int = 0 {
        didSet { selection = index }
    }
    
    var body: some View {
        HStack {
            Spacer()
            Button(action: { index = 0 }, label: { Text("Tab 1") })
                .foregroundColor(Color(uiColor: index == 0 ? .label : .secondaryLabel))
            Spacer()
            Button(action: { index = 1 }, label: { Text("Tab 2") })
                .foregroundColor(Color(uiColor: index == 1 ? .label : .secondaryLabel))
            Spacer()
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Harry Blue
  • 4,202
  • 10
  • 39
  • 78
  • It's really hard to understand what exactly you want to achieve and what you got so far. Is it possible to attach a screenshot of the current result and a simple wireframe of the desired one? – lazarevzubov Oct 28 '22 at 07:09

0 Answers0