You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:12:18