SwiftUI中FullScreenCover报错:已有有效定向事务令牌时请求新令牌
SwiftUI fullScreenCover过渡时的定向事务令牌错误
问题描述
使用SwiftUI的fullScreenCover修饰符时,在关闭当前视图并展示新视图的全屏过渡过程中,触发以下断言错误:
A new orientation transaction token is being requested while a valid one already exists
错误发生时,窗口与场景方向均为portrait,且存在一个原始方向同样为portrait的活跃定向事务令牌。
已尝试的无效方案:
- 显式设置windowOrientation与sceneOrientation
- 用NavigationStack包裹fullScreenCover的目标视图
- 展示新视图时调用
presentationMode.wrappedValue.dismiss()关闭当前视图
错误日志
2023-06-10 21:37:10.137760+0300 SignEase[50521:19426350] [Assert] A new orientation transaction token is being requested while a valid one already exists. reason=Fullscreen transition (dismissing): fromVC=<__TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView__: 0x13b80f200>; toVC=<__TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView__: 0x13a8d7c00>;;; windowOrientation=portrait; sceneOrientation=portrait; existingTransaction=<__UIForcedOrientationTransactionToken: 0x280b814a0; state: active; originalOrientation: portrait (1)>
相关代码
import SwiftUI import Firebase import FirebaseCore import FirebaseAuth @available(iOS 16.0, *) struct SignUp: View { @StateObject private var viewModal = SignViewData() @Environment(\.presentationMode) var presentationMode @State private var mainView = false @State private var SignInView = false var body: some View { ZStack { VStack(alignment: .leading){ Text("Sign Up") .font(.largeTitle) .fontWeight(.bold) .foregroundStyle(.linearGradient(colors: [.pink.opacity(0.6), .primary.opacity(0.5)], startPoint: .topLeading, endPoint: .bottomTrailing)) .padding(.leading,10) .padding(.bottom,20) Section{ TextField("", text: $viewModal.text) .textContentType(.emailAddress) .keyboardType(.emailAddress) .autocapitalization(.none) .disableAutocorrection(true) .placeholder(when: viewModal.text.isEmpty) { Text("Email address") .foregroundColor(.primary) .blendMode(.overlay) } .customField(icon: "envelope.open.fill") SecureField("", text: $viewModal.password) .textContentType(.password) .placeholder(when: viewModal.password.isEmpty) { Text("Password") .foregroundColor(.primary) .blendMode(.overlay) } .customField(icon: "key.fill") } .padding(.leading,10) .padding(.trailing,10) .padding(.bottom,10) Button { Task{ do{ try await viewModal.signUp() if viewModal.value == true{ DispatchQueue.main.async { // Add DispatchQueue.main.async block mainView.toggle() } } return } catch { print(error) } } } label: { ButtonView(title: "Create Account") } .padding(.leading,10) .padding(.trailing,10) .fullScreenCover(isPresented: $mainView) { // Any time i segue into this view i keep getting the error down below NavigationStack{ RootView() } } Divider() .padding(5) .padding(.leading,10) .padding(.trailing,10) HStack{ Text("Already have an account?") .font(.subheadline) .foregroundStyle(.linearGradient(colors: [.pink.opacity(0.7), .primary.opacity(0.5)], startPoint: .topLeading, endPoint: .bottomTrailing)) Button { SignInView.toggle() } label: { Text("Sign In") .font(.subheadline) .fontWeight(.semibold) .foregroundColor(.black) } } .fullScreenCover(isPresented:$SignInView){ NavigationStack{ SignIn() } } .padding(.leading,20) }.padding(15) .frame(width: 400,height: 370) .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 30, style: .continuous)) .shadow(color: Color("Shadow").opacity(0.3), radius: 10, x: 0, y: 10) .strokeStyle(cornerRadius: 30) .padding(20) }.background( Image("Background 4") ) } } @available(iOS 16.0, *) struct SignUp_Previews: PreviewProvider { static var previews: some View { SignUp() } } extension View { func placeholder<Content: View>( when shouldShow: Bool, alignment: Alignment = .leading, @ViewBuilder placeholder: () -> Content) -> some View { ZStack(alignment: alignment) { placeholder().opacity(shouldShow ? 1 : 0) self } } }
解决方案尝试
1. 调整fullScreenCover的附加层级
将fullScreenCover从Button或HStack上移到最外层的容器(比如ZStack)上,避免视图层级嵌套导致的事务冲突:
ZStack { // 原有的VStack内容 } .background(Image("Background 4")) // 把fullScreenCover移到这里 .fullScreenCover(isPresented: $mainView) { NavigationStack{ RootView() } } .fullScreenCover(isPresented:$SignInView){ NavigationStack{ SignIn() } }
2. 延迟触发视图切换
在登录成功后,延迟一小段时间再切换mainView的状态,让当前视图的过渡状态先完成:
if viewModal.value == true{ DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { mainView.toggle() } }
3. 确保视图模型状态在主线程更新
检查SignViewData的signUp方法,确保value的更新操作在主线程执行:
func signUp() async throws { // 原有Firebase注册逻辑 // ... // 更新状态时切到主线程 DispatchQueue.main.async { self.value = true } }
4. 临时禁用自动旋转(workaround)
如果上述方法无效,可以在Info.plist中设置仅允许portrait方向,避免系统自动处理定向事务:
- 添加
UISupportedInterfaceOrientations数组,只保留UIInterfaceOrientationPortrait - 添加
UISupportedInterfaceOrientations~ipad数组(如果适配iPad),同样只保留UIInterfaceOrientationPortrait
内容的提问来源于stack exchange,提问作者abdul lawal
相关产品推荐
相关产品推荐

