SwiftUI:模态表隐藏 ProgressView

Posted

技术标签:

【中文标题】SwiftUI:模态表隐藏 ProgressView【英文标题】:SwiftUI: modal Sheet hides ProgressView 【发布时间】:2021-09-30 08:48:10 【问题描述】:

我试图在我的 SwiftUI 应用程序中拥有一个系统范围的进度条,所以我定义了这个视图(注意:我的目标是 iOS 13+):

import SwiftUI

struct LoadingView<Content>: View where Content: View 
    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View 
        GeometryReader  _ in
            ZStack 
                self.content()

                if self.isShowing 
                    VStack 
                        ActivityIndicator()
                        Text("Loading...")
                    
                
            
        
    


struct ActivityIndicator: UIViewRepresentable 
    typealias UIView = UIActivityIndicatorView
    fileprivate var configuration =  (_: UIView) in 

    func makeUIView(context: UIViewRepresentableContext<Self>) -> UIView  UIView() 
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<Self>) 
        uiView.startAnimating()
        configuration(uiView)
    

并且像这样在 ContenView.swift 中使用

import SwiftUI

struct ContentView: View 
    @EnvironmentObject var myViewModel: MyViewModel

    var body: some View 
        let isLoading = Binding<Bool>(
            get:  self.myViewModel.isLoading ,
            set:  _ in 
        )

        LoadingView(isShowing: isLoading) 
            NavigationView 
                Home()
            
            .navigationViewStyle(StackNavigationViewStyle())
        
    

其中 MyViewModel 是一个非常标准的 ViewModel,带有一个用于 isLoading 的 @Published var,Home() 是应用程序的主要入口点。

每当在 MyViewModel 中触发 isLoading 的某些操作完成时,进度条就会正确显示(和隐藏)。

但是,如果我通过 NavigationView 中的一个视图或使用 ContentView 本身来呈现.sheet,无论它隐藏进度条是什么。

即使我使用内置 14+ ProgressView 问题仍然存在。

.Zindex() 也无济于事。

无论.sheet.alert 或 SwiftUI 上可用的任何覆盖视图,是否有任何方法可以让该视图在显示时始终位于顶部?

提前致谢!

【问题讨论】:

无论如何,您的观察应该是预期的行为,因为工作表是 modal 视图。模态应该始终显示在“计算机”需要“人类”输入的任何其他视图之上。见wiki @CouchDeveloper 我明白你的意思。但是,如果我用LoadingView 视图将我的视图主体包含在.sheet 中,进度条实际上会出现在模式的顶部。似乎在打开工作表时,Apple 选择以一种非常孤立的方式将两层分开。 当然,当您在模态视图中显示加载指示器时,它会在位于顶部的模态视图中呈现。恕我直言,从用户体验的角度来看,有一个覆盖加载指示器的模式看起来很奇怪。应用程序不应该等到结果可用之前显示警报或工作表吗? Sheet 用于输入一些数据,这些数据会触发 MyViewModel(以及 isLoading 属性),并且这些触发器不一定在工作表关闭时发生。所以我在这里描述的行为。让每个 .sheet 都有自己的加载器是一种方式。从用户体验的角度来看,我支持你,在这种情况下,也许全局 ZIndex 会是实用的,但我不确定这是否是一个好习惯 @CouchDeveloper 能否请您根据您在 cmets 中写下的考虑来回答这个问题,以便我给予您应得的荣誉? 【参考方案1】:

正如在 cmets 中已经写的那样,模态视图将显示在任何其他视图的顶部modal 视图旨在建立人机交流,或 dialog(因此,modal 视图经常被命名为“Dialog”)。

观察到工作表(模态视图)覆盖加载指示器是预期行为。

但是,IMO 问题中描述并在 cmets 中细化的问题,可以很好地解决,而不会破坏模态视图的行为:

当您想要显示尚未完成或什至完全不存在的数据时,您可能会显示“空白”屏幕,除此之外,让视图模型生成一个视图状态,说明视图应该显示“输入表”。

所以最初,用户会在空白屏幕上看到一个输入表单。

一旦用户输入并提交表单(将在视图模型中处理),输入表就会消失(由视图模型生成的视图状态控制),并显示它下面的“空白”视图。

因此,视图模型现在可以呈现另一个工作表,或者它意识到输入已完成。

一旦输入完成,视图模型就会加载数据,由于这可能需要一段时间,它会在视图状态中相应地反映这一点,例如使用“加载”状态或标志。视图会相应地呈现它,这是“空白”视图上方的加载指示器。

当视图模型接收到数据时,它会清除加载状态并相应地设置视图状态,同时传递数据。

视图现在呈现数据视图。

如果加载任务失败,视图模型将组成​​一个视图状态,其中内容“不存在”并带有错误信息。

视图再次呈现这一点,可能会在“空白”视图上方显示带有消息的警报,因为仍然没有数据。

确保用户可以关闭错误警报,并且视图模型通过删除“模态错误”状态来处理它,但内容仍然“不存在”。

现在,用户正盯着一个空白视图。您可以在此处嵌入错误消息,甚至添加“重试”按钮。在任何情况下,请确保用户可以离开该屏幕。

等等。 ;)

【讨论】:

以上是关于SwiftUI:模态表隐藏 ProgressView的主要内容,如果未能解决你的问题,请参考以下文章

带有表单的 SwiftUI 模态表:设备旋转后左/右填充错误

为啥 SwiftUI 模态视图在此处更新父变量(附代码)

在 iPad 上具有自定义大小的 SwiftUI sheet() 模态

无法在 SwiftUI 中使用 ForEach 和 CoreData 将数据正确传递给模态演示

SwiftUI - 动画过渡

从 NavigationView 呈现的 SwiftUI 关闭模式表(Xcode Beta 5)