Problem: My TabView
with PageTabViewStyle
has content of different heights. I can swipe between different pages, however inside the ScrollView
my TabView
shrinks to 0 height.
Expected: TabView
has height of the largest child view.
I have encountered similar problem before, but just hardcoded approximate frame height of largest view, but it doesn't seem right way to go. Any ideas much appreciated.
struct ContentView: View {
var body: some View {
// ScrollView {
VStack {
TabView {
ForEach(1..<5, id:\.self) { index in
VStack {
DifferentSizeViews(times: index)
Spacer()
}
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
Text("Some other content")
}
}
// }
}
struct DifferentSizeViews: View {
var times: Int
var body: some View {
VStack {
ForEach(0..<times, id:\.self) { index in
Text("some text \(index)")
}
}
}
}
After many hours of pain I found this solution. Hope it helps.
@State var selection: Int = 0
@State var height: CGFloat = 0
@State var sizeArray: [CGSize] = [.zero, .zero, .zero]
@State var initialHeight: CGFloat = 0
var body: some View {
ScrollView {
VStack(spacing: 0) {
Color.red
.frame(height: 100)
TabView(selection: $selection) {
Text("1\n1\n1")
.fixedSize()
.readSize(onChange: { size in
sizeArray[0] = size
if initialHeight == 0 {
initialHeight = size.height
}
})
.tag(0)
Text("2\n2\n2\n2\n2")
.fixedSize()
.readSize(onChange: { size in
sizeArray[1] = size
})
.tag(1)
Text("3")
.fixedSize()
.readSize(onChange: { size in
sizeArray[2] = size
})
.tag(2)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.background(Color.white)
.frame(height: height)
.onChange(of: selection) { newValue in
withAnimation {
height = sizeArray[newValue].height
}
}
.onChange(of: initialHeight) { newValue in
height = newValue
}
}
}
.background(Color.green)
}
And View
extension
extension View {
func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self, perform: onChange)
}
}
Although this might seem pretty hard-coded and kind of wrong, actually it's a quick fix as long as you know how the approximate height ratio you want for the TabView:
//MARK: - Body
var body: some View {
ScrollView(.vertical, showsIndicators: false, content: {
VStack(spacing: 0) {
SomeTabView()
.frame(height: UIScreen.main.bounds.width / 1.475)
.padding(.vertical, 20)
} //: VStack
}) //: ScrollView
}
In this code snippet, the number 1.475 is completely up to you in the modifier ".frame(height: UIScreen.main.bounds.width / 1.475)"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With