Reputation: 427
I want to make a segment tab page in SwiftUI such as bellow.
My code is as bellow:
struct ContentView: View {
@State var index = 0
@State private var offset: CGFloat = 0
var body: some View {
VStack(spacing: 0) {
HStack() {
Button("tab1") {
self.index = 0
}
Button("tab2") {
self.index = 1
}
}
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center, spacing: 0) {
VStack() {
List {
VStack {
HStack() {
Text("tab1 line1")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line1")
}
}
VStack {
HStack() {
Text("tab1 line2")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
VStack() {
List {
VStack {
HStack() {
Text("tab2 line1")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line1")
}
}
VStack {
HStack() {
Text("tab2 line2")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.onAppear() {
print("load")
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
}
}
.content
.offset(x: self.getOffset())
.animation(.spring())
.frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
.background(Color.gray)
}
private func getOffset() -> CGFloat {
let offset = CGFloat(self.index) * (-UIScreen.main.bounds.size.width)
return offset
}
}
Everything works well expect the onTapGesture in tab2. When tap the line of "tab1",the onTapGesture works well to print "click tab1 line1" or "click tab1 line2". After click button "tab2", the page will scroll to tab2 page. When click the line of list "tab2", onTapGesture not works.
I try a day, and found two methods to make it works:
.cornerRadius(30)
, the click in tab2 page will also works.I just want to keep the radius of list. How to fix this incredible bug?
Upvotes: 1
Views: 1498
Reputation: 30308
The problem is here:
.content
.offset(x: self.getOffset())
This duplicates the scrollview's content and offsets it to the right. As a result, what you are tapping is the duplicated content, which probably affects the tap gesture.
Instead, use ScrollViewReader
to scroll the ScrollView
, and remove your getOffset
code.
struct ContentView: View {
@State var index = 0
@State private var offset: CGFloat = 0
var body: some View {
VStack(spacing: 0) {
HStack() {
Button("tab1") {
self.index = 0
}
Button("tab2") {
self.index = 1
}
}
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { proxy in
HStack(alignment: .center, spacing: 0) {
VStack() {
List {
VStack {
HStack() {
Text("tab1 line1")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line1")
}
}
VStack {
HStack() {
Text("tab1 line2")
Spacer()
}
.frame(height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab1 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
.id(0) /// set id here
VStack() {
List {
VStack {
HStack() {
Text("tab2 line1")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line1")
}
}
VStack {
HStack() {
Text("tab2 line2")
Spacer()
}
.frame(width: UIScreen.main.bounds.size.width, height: 126)
.contentShape(Rectangle())
.onTapGesture {
print("click tab2 line2")
}
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.onAppear() {
print("load")
}
}
.frame(width: UIScreen.main.bounds.size.width, height: 300)
.cornerRadius(30)
.id(1) /// also set id here
}
.onChange(of: index) { _ in /// scroll the ScrollView
withAnimation(.spring()) {
proxy.scrollTo(index)
}
}
}
}
.frame(width: UIScreen.main.bounds.size.width, alignment: .leading)
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
.background(Color.gray)
}
}
Upvotes: 1