如何在 iPhone 应用程序中的先前视图之上正确显示登录屏幕

问题描述 投票:0回答:1

我对 SwiftUI 还很陌生,因此非常感谢您的帮助。我有一个应用程序,其数据是私有的并且需要登录屏幕。我希望每次应用程序进入后台时都显示登录屏幕,但我需要应用程序保持状态(即,如果用户正在创建新项目并更改到另一个应用程序,我想要所有他输入的要保留的数据,如果应用程序被终止,我可以忍受数据丢失,但我想允许在应用程序之间暂时交换,以让用户在应用程序之间复制和粘贴数据)。

我一直在谷歌搜索解决方案,人们正在使用常规视图实现登录屏幕并根据某些状态变量显示它,但我发现这种方法效果不佳,因为:

  • 当用户切换到另一个应用程序时,状态不会保留
  • 或者,如果使用 .fullScreenCover 修饰符,则状态会保留,但如果您使用工作表修饰符呈现视图,则状态无法正常工作(基本上,登录屏幕呈现在工作表后面,当用户使用应用程序从后到前)。

我在一篇文章中读到(尽管它没有显示任何代码示例),方法是使用登录屏幕创建另一个场景并在场景之间切换,但我无法使用 SwiftUI 实现它。

到目前为止,我尝试通过让我的应用程序有两个 WindowGroup 来实现它,一个包含应用程序内容,另一个包含登录屏幕。就像下面这样:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup("MainScene") {
            MainView()
        }
        WindowGroup("LoginScene") {
            LoginScreenView()
        }
    }
}

但我不知道如何在场景之间进行切换。

ios swift iphone xcode swiftui
1个回答
0
投票

据我所知,您不能在一个应用程序中拥有多个

WindowGroup
。请参阅 此 WWDC 视频,了解您可以选择哪些顶级应用程序容器以及它们的用途。

正如评论中已经提到的,这取决于应用程序状态。您可以观察

scenePhase
环境属性的变化并相应地设置状态。

例如:

// pull the scenePhase var from the environment
@Environment(\.scenePhase) private var scenePhase
// this will hold the login state of the application
@State private var login: Bool = false

var body: some Scene {
    WindowGroup {
        Group{
            if login{
                // if the user is logged in show the content
                ContentView()
            } else{
                // Here should be some view with appropriate logic
                Button("login"){
                    login = true
                }
            }
        }
        // observe all scenePhase changes and invalidate the login
        .onChange(of: scenePhase) { newValue in
            login = false
        }
    }
}

ContentView
中,现在归结为保留之前的状态。您可以使用
@SceneStorage
@AppStorage
来保留要再次显示的值。由于您没有提到如何导航或显示这些视图,我只能推测。我提供了 2 个示例来说明如何实现这一点。

  1. 带有

    NavigationStack

     struct ContentView: View {
        @SceneStorage("navigation") var path: [String] = []
    
         var body: some View {
             NavigationStack(path: $path) {
                 Button("subView"){
                     path.append("subView")
                 }
                 .navigationDestination(for: String.self) { value in
                     if value == "subView"{
                         SubView()
                     }
                 }
             }
         }
     }
    
     struct SubView: View {
         // persist the values with @SceneStorage
         @SceneStorage("text1") private var text1: String = ""
         @SceneStorage("text2") private var text2: String = ""
    
         var body: some View {
             VStack{
                 Text("subView")
                 TextField("", text: $text1)
                     .textFieldStyle(.roundedBorder)
                     .padding()
                 TextField("", text: $text2)
                     .textFieldStyle(.roundedBorder)
                     .padding()
             }
         }
     }
    
     // this extension is used to store an array of any Codable in UserDefaults
     extension Array: RawRepresentable where Element: Codable{
         public typealias RawValue = String
         // encode the array or save empty array if it fails
         public var rawValue: RawValue{
             guard let data = try? JSONEncoder().encode(self), let coded = String(data: data, encoding: .utf8) else {
                 return "[]"
             }
    
             return coded
         }
         // decode the string to an array or empty if it fails
         public init?(rawValue: RawValue) {
             guard let data = rawValue.data(using: .utf8), let decoded = try? JSONDecoder().decode(Self.self, from: data) else {
                 self = []
                 return
             }
    
             self = decoded
         }
     }
    
  2. 带有一张显示

    SubView
    的表格。在这里,我们需要存储自己显示和隐藏工作表的值。当关闭视图或将视图移动到背景时,SwiftUI 会将值设置为
    false

     struct ContentView: View {
         // load the saved value from UserDefaults
         @State private var showSheet: Bool = UserDefaults.standard.bool(forKey: "sheet")
    
         var body: some View {
             Button("show sheet"){
                 showSheet = true
             }.sheet(isPresented: $showSheet, content: {
                 SubView()
             })
             .onChange(of: showSheet) { newValue in
                 // store changed value to UserDefaults
                 UserDefaults.standard.setValue(newValue, forKey: "sheet")
             }
         }
     }
    

这当然只是一个粗略的实现,还可以进行大量的改进。但它应该让你朝着正确的方向前进。

© www.soinside.com 2019 - 2024. All rights reserved.