SwiftUI工作表不会取消



使用Swift5.2.3、iOS14.4.2、XCode12.4、

在SwiftUI中使用.sheet修饰符一开始让我感到兴奋,因为这似乎是显示模式表的一种简单有效的方式。

然而,在现实世界的应用程序中,事实证明.sheet几乎已经准备好进行集成。

以下是发现的两个错误:

错误1:纸张不会偶尔关闭

错误2:具有DefaultPickerStyle的Picker在工作表的SegmentPicker内时不工作(请参阅我创建的这个Stackloverlow问题(

现在让我们关注Bug Nr1:;片材不闭合":

cmdpresentationMode.wrappedValue.dismiss()应该关闭工作表。它适用于90%的情况。但是,模态表经常不停地结束,而且没有给出任何原因。

以下是代码摘录:

import SwiftUI
import Firebase
struct MyView: View {

@Environment(.presentationMode) var presentationMode

var body: some View {

VStack {
Form {
Section(header: Text("Login")) {
Button(action: {
UserDefaults.standard.set(true, forKey: AppConstants.UserDefaultKeys.justLogoutLoginPressed)
try? Auth.auth().signOut()

// supposedly should work all the time - but it only works 90% of the time.....
presentationMode.wrappedValue.dismiss()
}) {
HStack {
Text((Auth.auth().currentUser?.isAnonymous ?? true) ? "Login" : "Logout")
Spacer()
}
}
}
}
.ignoresSafeArea()
Spacer()
}
}
}

我还试图将结束调用封装在主线程中:

DispatchQueue.main.async {
presentationMode.wrappedValue.dismiss()
}

但这无济于事。

知道为什么SwiftUI.sheets不使用presentationMode关闭它吗??

在这里,我首先添加了表单的调用方式。由于从一个更大的应用程序中取出,我显然只在这里展示了一个关于如何调用表单的示例:

import SwiftUI
@main
struct TestKOS005App: App {
@StateObject var appStateService = AppStateService(appState: .startup)

var body: some Scene {
WindowGroup {
MainView()
.environmentObject(appStateService)
}
}
}
class AppStateService: ObservableObject {

@Published var appState: THAppState
var cancellableSet = Set<AnyCancellable>()

init(appState: THAppState) {

self.appState = appState                
}
// ...
}
enum THAppState: Equatable {

case startup
case downloading
case caching
case waiting
case content(tagID: String, name: String)
case cleanup
}
struct MainView: View {

@EnvironmentObject var appStateService: AppStateService
@State var sheetState: THSheetSelection?

init() {
UINavigationBar.appearance().tintColor = UIColor(named: "title")
}

var body: some View {

ZStack {
NavigationView {

ZStack {
switch appStateService.appState {
case .caching:
Text("caching")
case .waiting:
Text("waiting")
case .content(_, _):
VStack {
Text("content")
Button(action: {
sheetState = .sheetType3
}, label: {
Text("Button")
})
}
default:
Text("no screen")
}
}
.sheet(item: $sheetState) { state in
switch state {
case .sheetType1:
Text("sheetType1")
case .sheetType2:
Text("sheetType2")
case .sheetType3:
MyView()
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}
enum THSheetSelection: Hashable, Identifiable {

case sheetType1
case sheetType2
case sheetType3

var id: THSheetSelection { self }
}

我认为在注销时,您可能会有一个实例检查Firebase Auth是否有活动的用户会话,并在调用try? Auth.auth().signOut()时将视图更改为登录屏幕,这可能会阻止调用presentationMode.wrappedValue.dismiss()

您可能希望在MainView中创建一个state属性,并在

MyView在MyView中;而不是直接调用signout((

struct MyView: View {

@Environment(.presentationMode) var presentationMode
@Binding var logoutTapped: Bool

var body: some View {

VStack {
Form {
Section(header: Text("Login")) {
Button(action: {
UserDefaults.standard.set(true, forKey: AppConstants.UserDefaultKeys.justLogoutLoginPressed)
// try? Auth.auth().signOut() -> instead of this directly
logoutTapped = true // call this
// supposedly should work all the time - but it only works 90% of the time.....
presentationMode.wrappedValue.dismiss()
}) {
HStack {
Text((Auth.auth().currentUser?.isAnonymous ?? true) ? "Login" : "Logout")
Spacer()
}
}
}
}
.ignoresSafeArea()
Spacer()
}
}
}

在MainView中,创建工作表时,在onDismissal块中,设置logoutTapped bool状态的条件,并在那里注销,如下所示;

struct MainView: View {

@EnvironmentObject var appStateService: AppStateService
@State var sheetState: THSheetSelection?
@State var logoutTapped = false

init() {
UINavigationBar.appearance().tintColor = UIColor(named: "title")
}

var body: some View {

ZStack {
NavigationView {

ZStack {
switch appStateService.appState {
case .caching:
Text("caching")
case .waiting:
Text("waiting")
case .content(_, _):
VStack {
Text("content")
Button(action: {
sheetState = .sheetType3
}, label: {
Text("Button")
})
}
default:
Text("no screen")
}
}
.sheet(item: $sheetState) {
if logoutTapped { // if this is true call signout
Auth.auth().signout()
}
} content: { state in
switch state {
case .sheetType1:
Text("sheetType1")
case .sheetType2:
Text("sheetType2")
case .sheetType3:
MyView(logoutTapped: $logoutTapped) // send logoutTapped to MyView
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}

最新更新