Ste*_*n.W 10 ios swift swiftui
故事有点长。首先,让我展示一些无法按我预期工作的代码。
import SwiftUI
struct ContentView: View {
@State var isPresentingAlert = false
@State var isPresentingSheet = false
var body: some View {
VStack {
Button("Show Sheet") {
isPresentingSheet = true
}
}
.alert("Alert", isPresented: $isPresentingAlert) {}
.sheet(isPresented: $isPresentingSheet) {
Button("Show Alert") {
isPresentingAlert = true
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码的意图很明确:当用户按下“显示工作表”按钮时,视图应该显示一个工作表,并且工作表上有一个“显示警报”按钮,这应该会导致点击后显示警报窗口。代码被简化 - 在原始应用程序中,工作表向用户显示一个表单,并且当用户提交包含一些无效数据的表单时应显示警报。
但实际上,当我按下“显示警报”按钮时,警报并未显示。相反,我在控制台中收到以下错误:
2023-02-14 23:41:08.163349+0800 SheetAndAlert[8351:217492] [Presentation] Attempt to
present <SwiftUI.PlatformAlertController: 0x15b030600> on
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x15b00aa00> (from
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x15b00aa00>) which is already presenting
<_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x15b02e000>.
Run Code Online (Sandbox Code Playgroud)
我不知道这个错误意味着什么。后来我更改了代码以使用 UIKIt's UIAlertController,希望我可以解决该错误。(代码改编自这个答案:How do I Present a UIAlertController in SwiftUI?)
2023-02-14 23:41:08.163349+0800 SheetAndAlert[8351:217492] [Presentation] Attempt to
present <SwiftUI.PlatformAlertController: 0x15b030600> on
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x15b00aa00> (from
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x15b00aa00>) which is already presenting
<_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x15b02e000>.
Run Code Online (Sandbox Code Playgroud)
但它仍然不起作用。抛出类似的错误:
2023-02-14 23:56:12.715039+0800 SheetAndAlert[9991:263667] [Presentation] Attempt to
present <UIAlertController: 0x13d80b800> on
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x139012600> (from
<_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__:
0x139012600>) which is already presenting
<_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x13b02fc00>.
Run Code Online (Sandbox Code Playgroud)
最后我找到了一个可行的解决方案,只需移入.alert的.sheet内容即可:
import SwiftUI
struct ContentView: View {
@State var isPresentingAlert = false
@State var isPresentingSheet = false
var body: some View {
VStack {
Button("Show Sheet") {
isPresentingSheet = true
}
}
.sheet(isPresented: $isPresentingSheet) {
Button("Show Alert") {
ContentView.alertMessage(title: "Alert", message: "Alert")
}
}
}
static func alertMessage(title: String, message: String) {
let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) { (action: UIAlertAction) in
}
alertVC.addAction(okAction)
let viewController = UIApplication.shared.windows.first!.rootViewController!
viewController.present(alertVC, animated: true, completion: nil)
}
}
Run Code Online (Sandbox Code Playgroud)
虽然有效,但我仍然不明白(完全!)为什么使用UIAlertController不能解决问题,而只需将修改器移到另一个地方就可以。
TL;DR:此行为是 SwiftUI 使用的 UIKit 层的约束,解决方案是您已经找到的,以显示来自修改器主体的警报.sheet。
您看到的行为是由 SwiftUI 依赖的底层 UIKit 层引起的。
在 UIKit 中,内容由 管理UIViewControllers,每个视图控制器都可以在其之上呈现另一个视图控制器,但只能有一个。这通常用于呈现“模式”(或工作表)、“弹出窗口”和“警报”。
使用 SwiftUI 时,视图控制器对我们来说是不可见的,但它们仍然存在。一些 SwiftUI 结构映射到一些 UIKit 视图控制器,例如NavigationViewtoUINavigationController和TabViewto UITabViewController。
正如您现在可能已经猜到的,.sheet和.alert修饰符映射到它们自己的视图控制器。.sheet特别创建一个新的视图控制器,该视图控制器呈现在当前视图控制器之上。
正如我之前提到的,UIKit 中的视图控制器在任何时候只能呈现一个视图控制器。因为两个修饰符都修改相同的内容,因此修改相同的视图控制器,所以尝试同时激活这两个修饰符将会给您带来该错误。
您已经找到了修复方法:将.alert修改器移动到的主体内.sheet将导致警报显示在工作表视图控制器上。
Iva*_*čin -1
如果你真的需要这个,我认为只有一些 hacky 解决方案:
.sheet(isPresented: $isPresentingSheet) {
Button("Show Alert") {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
isPresentingAlert = true
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想到的另一个解决方案是,您可以从那里监视.onChange并isPresentingSheet调用警报(我还没有测试过这个,它最终可能asyncAfter也需要)。显然,您需要添加更多变量来了解发生了什么,sheet因为每次解雇都不应该调用警报。它不那么老套,但实现起来更复杂,整体可读性也较差。
| 归档时间: |
|
| 查看次数: |
2347 次 |
| 最近记录: |