在SwiftUI中,是否有一种方法可以根据一个可选绑定是否有值返回不同的视图?

3

我正在尝试在我的视图模型中获取一些数据后显示一个视图(因为数据可能是可选的,因为视图模型仅在请求时获取它)。

为什么以下操作不可行 / 我该怎么做?

@Binding var someViewModel: SomeViewModel?

var body: some View {
    if let viewModel = self.someViewModel {
        return filledView(with: viewModel)
    }
    return emptyView()
}

这里出现问题的部分是Swift UI视图生成器中的 if let 。一种解决方案是设置一个单独的布尔值,表示数据已加载,或者甚至使用枚举来标识何时数据可用以及何时不可用,但这样会导致视图代码充满可选值检查,这并不理想。例如,我想避免做以下事情:
Image(systemName: someViewModel?.icon.symbol() ?? "plus_sign")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 60, height: 60)
                    .foregroundColor(Color.red)
                    .padding()

非常感谢您的帮助。

2个回答

5

您可以使用map方法。如果可选项具有某个值,则它将取消封装该值,否则它将完全忽略:

var body: some View {
    Group {
        someViewModel.map { FilledView(with: $0) }
    }
}

谢谢!看来有不止一种选择。好东西 :) - Lewion
4
Group 比 AnyView 更加高效。AnyView 会阻止编译器优化不必要的层级。如果您在编译时知道可能的视图,请始终使用 Group。只有当可能的视图列表未知时,才应该使用 AnyView。 - Rob Napier
感谢您的解释,Rob! - Lewion
我看到这里的文档 https://developer.apple.com/documentation/swift/optional/1539476-map 对可选类型应用 map 函数会产生另一个可选类型。那么这意味着我们在 Group 中返回了一个可选视图。这是如何工作的? - Anirudh Bandi

3

刚刚发现另一个选项,我们可以使用 AnyView 来包裹空的和有内容的视图函数返回值,这样问题也会消失。

空视图的示例代码如下:

func emptyView() -> AnyView {
        return AnyView(Text(""))
    }

填充视图的示例如下:

func filledView(for viewModel: SomeViewModel) -> AnyView {
    return AnyView(VStack(alignment: .leading) {
        Image(systemName: viewModel.icon.symbol())
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 60, height: 60)
                    .foregroundColor(Color.red)
                    .padding()
        }
    }
}

这似乎是一个简单的解决方法。AnyView 有什么缺点吗? - Jake Cronin
是的,它可以工作,但可能会在预览方面出现问题。错误信息如下:无法将返回类型为“AnyView”的返回表达式转换为返回类型“some View” - Stephen Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接