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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:19:54