SwiftUI如何避免sheet中的键盘上推主UI界面元素
解决方案
问题原因
- 修饰符顺序错误:你当前把
.ignoresSafeArea修饰符加在了.sheet()之后,SwiftUI的修饰符是顺序生效的,.sheet()会返回一个全新的sheet容器视图,后续添加的忽略安全区规则实际作用于sheet而非底层主界面,所以主界面依然会响应键盘安全区变化。 - 键盘事件冒泡:sheet收起时如果键盘处于激活状态,系统会同步触发键盘安全区高度变更事件,该事件会传递到底层主界面,触发布局调整导致元素位移。
可直接使用的修复方案
方案1:调整修饰符顺序(最简单)
把.ignoresSafeArea移到.sheet()之前,让规则直接作用于主界面的VStack即可:
private var welcomeSection5: some View { ZStack { VStack { // This is the part that moves up and down TellSlideView(text: "And what's your age \(userName) if I may?") Spacer() Button(action: { displaySheet.toggle() }, label: { Text("Enter age") .padding() .foregroundColor(Color.white) .frame(maxWidth: .infinity) .background(Color.MyTheme.Purple) .cornerRadius(15) .padding(.horizontal) .padding(.bottom, 40) }) } .ignoresSafeArea(.keyboard, edges: .bottom) // 移到sheet前面 .sheet(isPresented: $displaySheet) { AddUserAgeView(onboardingState: $onboardingState) } } }
方案2:关闭sheet前先收起键盘(适配所有场景)
如果调整顺序后依然有问题,可以在触发sheet关闭前先强制收起键盘,等键盘动画结束后再关闭sheet,从根源避免键盘事件传递到主界面:
Button(action: { // 强制收起所有激活的键盘 UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) // 等待键盘收起动画完成后再关闭sheet,动画时长默认0.15秒可根据需求调整 DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { displaySheet.toggle() } }, label: { Text("Enter age") .padding() .foregroundColor(Color.white) .frame(maxWidth: .infinity) .background(Color.MyTheme.Purple) .cornerRadius(15) .padding(.horizontal) .padding(.bottom, 40) })
如果sheet内部有自定义关闭按钮,在内部的关闭逻辑中也加上上述收起键盘的逻辑即可。
方案3:全局忽略键盘安全区
如果你的整个应用都不需要界面跟随键盘调整布局,可以直接在根视图上加全局忽略规则,一劳永逸解决所有同类问题:
@main struct YourAppName: App { var body: some Scene { WindowGroup { // 你的根视图 OnboardingRootView() .ignoresSafeArea(.keyboard, edges: .bottom) } } }
内容的提问来源于stack exchange,提问作者Charlie Maréchal
相关产品推荐
相关产品推荐

