iOS 15更新后SwiftUI自定义App Bar内所有元素无法点击如何解决
问题原因
iOS 15 对 SwiftUI 视图的交互区域判定逻辑做了调整,默认只有视图的内容绘制区域会响应点击事件。你的自定义 App Bar 顶部延伸到了状态栏安全区域之外,这部分区域默认不会被判定为可交互范围,同时你将空的 NavigationLink 和按钮放在同一 HStack 层级,也可能存在交互遮挡的问题。
解决方案
按以下步骤修改代码即可修复点击失效问题:
- 给承载整个 App Bar 的 VStack 添加
.contentShape(Rectangle())修饰符,明确指定整个 VStack 的矩形区域都可响应交互 - 调整 NavigationLink 的位置,不要和按钮放在同一布局层级,避免遮挡按钮交互
- 替换 iOS 15 已废弃的 Window 获取 API,避免后续版本出现异常
修改后的完整代码
struct appBar: View { @Binding var index: Int @State var showGoalTipsScreen = false var body: some View { // 把NavigationLink移到最外层,避免遮挡按钮 ZStack { NavigationLink("", destination: GoalTipsView().navigationBarHidden(true), isActive: $showGoalTipsScreen) VStack(spacing: 25) { HStack { Text("My Goals") .fontWeight(.bold) .font(.title) .foregroundColor(.white) Spacer(minLength: 0) Button(action: { showGoalTipsScreen = true }) { Text("Add New Goal") .foregroundColor(.white) Image("addIcon") .resizable() .frame(width: 18, height: 18) .foregroundColor(.white) } } HStack { Button(action: { self.index = 0 }, label: { VStack { Text("Active") .foregroundColor(.white) .fontWeight(self.index == 0 ? .bold : .none) Capsule().fill(self.index == 0 ? Color.white : Color.clear) .frame(height: 4) } }) Button(action: { self.index = 1 }, label: { VStack { Text("Completed") .foregroundColor(.white) .fontWeight(self.index == 1 ? .bold : .none) Capsule().fill(self.index == 1 ? Color.white : Color.clear) .frame(height: 4) } }) Button(action: { self.index = 2 }, label: { VStack { Text("Shared") .foregroundColor(.white) .fontWeight(self.index == 2 ? .bold : .none) Capsule().fill(self.index == 2 ? Color.white : Color.clear) .frame(height: 4) } }) }.padding(.bottom, 10) } .padding(.horizontal) // 替换适配iOS15+的安全区域获取方式 .padding(.top, (UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .compactMap({$0 as? UIWindowScene}) .first?.windows .first(where: \.isKeyWindow)?.safeAreaInsets.top ?? 0) + 10) .background(RoundedCorners(tl: 0, tr: 0, bl: 13, br: 13).fill(Color.blue)) // 核心修改:明确指定整个矩形区域都可响应交互 .contentShape(Rectangle()) } } }
修改说明
.contentShape(Rectangle())会强制 SwiftUI 将整个视图的矩形范围都判定为可交互区域,不管内容有没有绘制到对应位置,直接解决安全区域外部分点击无响应的问题- 把 NavigationLink 移到 ZStack 最底层,避免空的导航链接视图占用交互区域,挡住后面按钮的点击事件
- 新的 Window 获取方式适配了 iOS 15+ 的系统 API 规范,避免后续系统版本升级出现崩溃问题
内容的提问来源于stack exchange,提问作者Filia Salta
相关产品推荐
相关产品推荐

