SwiftUI中绑定onTapGesture的systemImage点击无效问题求助
问题
在SwiftUI中用绑定了onTapGesture的systemImage切换布尔变量queryView实现视图切换,通过position(x:,y:)把图标定位在屏幕左上角,但当y值小于100时,onTapGesture触发不了。
补充说明:用这个带点击手势的图标是因为NavigationLink返回按钮的视图过渡太卡,想让点击手势在屏幕任意位置都能正常工作。
代码如下:
import SwiftUI import FirebaseFirestoreSwift import Firebase struct ChatView: View { @Environment(\.presentationMode) var presentationMode @StateObject var homeData:HomeModel @State var queryView:Bool = false @EnvironmentObject var model:ContentModel var user = Auth.auth().currentUser let db = Firestore.firestore() //If it is the first time when user scrolls @State var scrolled = false // @GestureState var isLongPressed = false var body: some View { if queryView == false { VStack(spacing: 0) { Text("\(homeData.query) Global Chat").foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))).font(.title3).padding(.top, 30) Text("Welcome \(model.firstName) \(model.secondName) !").foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))).font(.callout) Image(systemName: "arrow.backward.square") .position(x: 30, y: 0) .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.system(size: 30, weight: .regular)) .onTapGesture { withAnimation(.easeOut) { queryView = true } print("TAPPED") } ScrollViewReader { reader in ScrollView{ VStack(spacing: 15) { ForEach(homeData.msgs) { msg in ChatRow(chatData: msg, firstName: model.firstName, secondName: model.secondName).onAppear(){ if msg.id == self.homeData.msgs.last!.id && !scrolled { reader.scrollTo(homeData.msgs.last!.id, anchor: .bottom) scrolled = true } // print(model.firstName) // print(model.secondName) } }.onChange(of: homeData.msgs) { value in reader.scrollTo(homeData.msgs.last!.id, anchor: .bottom) } } }.padding(.vertical) }.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height - 135) HStack(spacing:15) { TextField("Enter message", text: $homeData.txt) .padding(.horizontal) //Fixed height for animation... .frame(height: 45) .foregroundColor(Color(.black)) .background(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1)).opacity(1.0)) .clipShape(Capsule()) if homeData.txt != "" { Button { homeData.writeAllMessages() } label: { Image(systemName: "paperplane.fill") .font(.system(size: 22)) .foregroundColor(.white) .frame(width: 45, height: 45) .background(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .clipShape(Circle()) } } }.animation(.default) .padding() Spacer().frame(height: 100) }.background(Color(.black).scaledToFill().frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height).ignoresSafeArea()) .navigationBarBackButtonHidden(true) } else { QueryView(query: homeData.query) } } }
解决方案
1. 用HStack替代position布局,保证交互区域有效
position是绝对坐标定位,一旦视图进入安全区域(比如顶部状态栏)或者被其他视图层级遮挡,点击就会失效。改用HStack把返回按钮和标题放在同一栏,既能固定在左上角,又能确保点击区域正常:
VStack(spacing: 0) { // 顶部栏改用HStack布局,将返回按钮放在左侧 HStack { Image(systemName: "arrow.backward.square") .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.system(size: 30, weight: .regular)) .onTapGesture { withAnimation(.easeOut) { queryView = true } print("TAPPED") } Spacer() // 把标题放在中间 VStack(spacing: 4) { Text("\(homeData.query) Global Chat") .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.title3) Text("Welcome \(model.firstName) \(model.secondName) !") .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.callout) } Spacer() } .padding(.top, 30) .padding(.horizontal, 16) // 后续ScrollView等内容保持不变 ScrollViewReader { reader in // ... 原有代码 ... } // ... 原有代码 ... }
2. 若坚持用position,需允许视图延伸到安全区域
给图标添加ignoresSafeArea,让它能延伸到顶部安全区域,同时调整y值到合理范围(比如40,避开状态栏最顶部的不可交互区):
Image(systemName: "arrow.backward.square") .position(x: 30, y: 40) .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.system(size: 30, weight: .regular)) .ignoresSafeArea(.container, edges: .top) // 允许视图延伸到顶部安全区 .onTapGesture { withAnimation(.easeOut) { queryView = true } print("TAPPED") }
3. 调整视图层级,避免被ScrollView遮挡
你的代码中ScrollView高度设为UIScreen.main.bounds.size.height - 135,可能会覆盖顶部的图标。把返回图标放在VStack的最顶部,确保层级在ScrollView之上:
VStack(spacing: 0) { // 返回图标放在最顶部,优先于ScrollView渲染 Image(systemName: "arrow.backward.square") .position(x: 30, y: 40) .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.system(size: 30, weight: .regular)) .onTapGesture { withAnimation(.easeOut) { queryView = true } print("TAPPED") } // 标题视图移到图标下方 Text("\(homeData.query) Global Chat") .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.title3) .padding(.top, 30) Text("Welcome \(model.firstName) \(model.secondName) !") .foregroundColor(Color(#colorLiteral(red: 0.5951357484, green: 0.5694860816, blue: 1, alpha: 1))) .font(.callout) // ... 后续视图 ... }
内容的提问来源于Stack Exchange,提问作者Micsa Dan
相关产品推荐
相关产品推荐

