So basically I am very new to SwiftUI(started a few days ago) and am trying to put tabs within a ScrollView
. The end result I am trying to achieve is that of Instagram's profile view.
I'd imagine the view's implementation would be something like this:
ScrollView {
VStack {
HStack {
// Profile Pic
// Stats
}
// Bio
// Button(s)
LazyVStack(pinnedViews: .sectionHeaders) {
Section {
TabView {
// Tab 1
// Tab 2
// Tab 3
}
} headers: {
// Tab icons
}
}
}
}
The problem is, the TabView never appears. Also I am unsure whether this is the best setup especially the LazyVStack
as I am only using to for the fact that it pins the headers. As I said previously, I'm super new to SwiftUI so there are definetly some views that I have no idea exist some of which might be useful in what I am trying to achieve.
Nonetheless, how can I achieve the layout I am going for?
Thank you!
Side Question: With the way that I have the view setup, the scrollbar for the view is for the entire view however in apps like Instagram, the scrollbars are only within the tabs themselves. How could I also incorporate that aspect into the solution? Thanks again!
CodePudding user response:
You are on the right track. TabView
when not used as the root loses the ability to resize it self properly.
So that's why we need to specfiy its minHeight
. You can use GeometryReader
for that.
Then just give TabView
a selection
in order for the Tab-Buttons to work and most likely you want to apply .tabViewStyle(.page(indexDisplayMode: .never))
in order to be able to swipe between them.
Working Demo:
GeometryReader { proxy in
ScrollView {
VStack {
HStack {
Image(systemName: "person.circle")
Text("Some Text")
}
}
LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
Section {
TabView(selection: $tabIndex) {
VStack {
Spacer()
Text("1")
Spacer()
}
.frame(maxWidth: .infinity)
.background(.red.opacity(0.5))
.tag(0)
VStack {
Spacer()
Text("2")
Spacer()
}
.frame(maxWidth: .infinity)
.background(.green.opacity(0.5))
.tag(1)
VStack {
Spacer()
Text("3")
Spacer()
}
.frame(maxWidth: .infinity)
.background(.blue.opacity(0.5))
.tag(2)
}
.tabViewStyle(.page(indexDisplayMode: .never))
.frame(maxWidth: .infinity, minHeight: proxy.size.height)
} header: {
HStack {
Button {
withAnimation {
tabIndex = 0
}
} label: {
Text("Tab 1")
}
.buttonStyle(.bordered)
Button {
withAnimation {
tabIndex = 1
}
} label: {
Text("Tab 2")
}
.buttonStyle(.bordered)
Button {
withAnimation {
tabIndex = 2
}
} label: {
Text("Tab 3")
}
.buttonStyle(.bordered)
}
.padding()
.frame(maxWidth: .infinity)
.background(.regularMaterial)
}
}
}
}
As to your side question: They most likely still use a single scrollview but then move the inset of the scroll indicators. You cannot do that with SwiftUI only but you would need to introspect the underlying UIScrollView
for that. SwiftUI-Introspect is good for that.
And then adjust the verticalScrollIndicatorInsets
to your needs