作为将爱好项目从 UIKit 转换为 SwiftUI 的一部分,我尝试从 SwiftUI 视图呈现 MFMailComposeViewController。它可以工作,但视图控制器没有像使用 UIKit 时那样从屏幕底部正确呈现。
例如,按照Hobbes the tige的这个答案,这是我得到的结果:
使用原始 UIKit 代码,相同的视图如下所示:
注意 SwiftUI 版本中屏幕底部看起来更糟糕。有没有办法解决?或者从 SwiftUI 呈现 MFMailComposeViewController 的更好方法?
这是基于上面链接的答案的测试应用程序的完整代码,展示了问题:
MailComposeTestApp.swift
import SwiftUI
@main
struct MailComposeTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView.swift
import SwiftUI
import MessageUI
struct ContentView: View {
@State var result: Result<MFMailComposeResult, Error>? = nil
@State var isShowingMailView = false
var body: some View {
Button(action: {
self.isShowingMailView.toggle()
}, label: {
Label("Send mail", systemImage: "envelope")
})
.disabled(!MFMailComposeViewController.canSendMail())
.sheet(isPresented: $isShowingMailView) {
MailView(result: self.$result)
}
}
}
MailView.swift:
import SwiftUI
import UIKit
import MessageUI
struct MailView: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentation
@Binding var result: Result<MFMailComposeResult, Error>?
class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
@Binding var presentation: PresentationMode
@Binding var result: Result<MFMailComposeResult, Error>?
init(presentation: Binding<PresentationMode>,
result: Binding<Result<MFMailComposeResult, Error>?>) {
_presentation = presentation
_result = result
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
defer {
$presentation.wrappedValue.dismiss()
}
guard error == nil else {
self.result = .failure(error!)
return
}
self.result = .success(result)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentation: presentation, result: $result)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailView>) -> MFMailComposeViewController {
let vc = MFMailComposeViewController()
vc.mailComposeDelegate = context.coordinator
return vc
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: UIViewControllerRepresentableContext<MailView>) {
}
}
在 PHPickerViewController 中看到同样的问题证实了我的怀疑,即这是 SwiftUI 中的普遍行为,并且使解决方案更容易追踪。
事实证明,您必须手动允许工作表视图溢出到底部的安全区域:
.sheet(isPresented: $isShowingMailView) {
MailView(result: self.$result)
.edgesIgnoringSafeArea(.bottom)
}
这似乎适用于以这种方式呈现的任何类型的视图。