【问题标题】:SwiftUI sheet does not dismissSwiftUI 工作表不会关闭
【发布时间】:2022-03-20 11:07:53
【问题描述】:

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

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

但是,在实际应用程序中,.sheet 几乎可以集成。

这里发现了两个错误:

错误 1:工作表不会偶尔关闭

错误 2:带 DefaultPickerStyle 的选取器在工作表的 SegmentPicker (See this Stackoverlow-question that I created) 内时不起作用

现在让我们关注 Bug Nr1:“工作表未关闭”:

cmd presentationMode.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 }
}

【问题讨论】:

  • 我在您的代码中没有看到工作表。请提供最小的可重现示例。
  • 请提供您从中调用MyView 的视图代码。
  • 我提供了您要求的代码。由于这是一个相当复杂的应用程序,我提供了整个应用程序的最小摘录。但这给了你这个想法。如您所见,通过按下按钮在 MainView 中的 NavigationView 内调用工作表。

标签: swiftui dismiss environmentobject modal-view


【解决方案1】:

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

您可能希望在 MainView 中创建一个 state 属性,并在 MyView 中创建一个相应的 Binding 属性,并使用它们管理退出状态,如下所示。

在我的视图中;而不是直接调用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())
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 2020-06-04
    • 2020-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多