SwiftUI中使用UIVideoEditorController的异常问题及解决方法咨询
解决SwiftUI中UIVideoEditorController代理不触发及全屏视图异常关闭问题
问题根源
- 代理方法不触发:你给
UIVideoEditorController的videoPath赋值了source.absoluteString,但该属性要求传入本地文件的纯路径字符串(不带file://前缀),而absoluteString返回的是包含scheme的完整URL字符串,导致编辑器无法正确识别视频文件,后续代理回调自然无法触发。 - 全屏视图异常关闭:你使用了SwiftUI的
@Environment(\.dismiss)来关闭视图,这个方法会直接操作SwiftUI的视图栈,而UIVideoEditorController本身是UIKit的模态导航控制器,二者的模态栈逻辑冲突,导致点击保存后连带关闭了上层的全屏覆盖视图。
修正方案
1. 修正VideoEditor实现
调整videoPath赋值逻辑,改用UIKit原生的dismiss方式,并实现完整的代理方法:
struct VideoEditor: UIViewControllerRepresentable { let source: URL let maxSeconds: TimeInterval let onSaved: (URL) -> Void let onCancel: () -> Void let onError: (Error) -> Void func makeUIViewController(context: Context) -> UIVideoEditorController { let editor = UIVideoEditorController() // 关键修正:使用本地文件纯路径,而非带scheme的absoluteString editor.videoPath = source.path editor.videoMaximumDuration = maxSeconds editor.videoQuality = .typeHigh editor.delegate = context.coordinator return editor } func updateUIViewController(_ uiViewController: UIVideoEditorController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator( onSaved: onSaved, onCancel: onCancel, onError: onError ) } class Coordinator: NSObject, UINavigationControllerDelegate, UIVideoEditorControllerDelegate { private let onSaved: (URL) -> Void private let onCancel: () -> Void private let onError: (Error) -> Void init(onSaved: @escaping (URL) -> Void, onCancel: @escaping () -> Void, onError: @escaping (Error) -> Void) { self.onSaved = onSaved self.onCancel = onCancel self.onError = onError } func videoEditorController(_ editor: UIVideoEditorController, didSaveEditedVideoToPath editedVideoPath: String) { let url = URL(fileURLWithPath: editedVideoPath) // 让编辑器自己dismiss,完成后再回调SwiftUI editor.dismiss(animated: true) { self.onSaved(url) } } func videoEditorControllerDidCancel(_ editor: UIVideoEditorController) { editor.dismiss(animated: true) { self.onCancel() } } func videoEditorController(_ editor: UIVideoEditorController, didFailWithError error: Error) { editor.dismiss(animated: true) { self.onError(error) } } } }
2. 调整ContentView的使用逻辑
在回调中手动更新SwiftUI的状态变量,确保视图状态同步:
struct ContentView: View { let videoToEdit: URL @State private var presentingFirstCover = false @State private var presentingEditor = false var body: some View { VStack { Button("Present first cover") { presentingFirstCover = true } } .fullScreenCover(isPresented: $presentingFirstCover) { VStack { Button("Present editor") { presentingEditor = true } } .fullScreenCover(isPresented: $presentingEditor) { VideoEditor( source: videoToEdit, maxSeconds: 20, onSaved: { url in print("saved edited video to: \(url)") presentingEditor = false }, onCancel: { presentingEditor = false }, onError: { error in print("edit error: \(error)") presentingEditor = false } ) .ignoresSafeArea() } } } }
关键说明
- 用
source.path替代absoluteString:确保UIVideoEditorController能正确读取本地视频文件,触发编辑流程和代理回调。 - 让编辑器自行dismiss:通过
editor.dismiss(animated:completion:)关闭UIKit模态控制器,避免干扰SwiftUI的视图栈,仅在回调中更新SwiftUI的状态变量,保持二者状态同步。 - 实现完整代理方法:覆盖保存、取消、失败三种场景,避免未处理的异常导致视图状态混乱。
内容的提问来源于stack exchange,提问作者wristbands
相关产品推荐
相关产品推荐

