如何使用SwiftUI@ViewBuilder创建需要参数的视图



在回答我关于如何将通用SwiftUI视图添加到另一个视图的问题时,我了解到这可以使用@ViewBuilder来完成。

虽然这对我的大多数用例来说都很好,但我现在遇到了一个新问题:

  • @ViewBuilder解决方案基本上在GenericView<Content: View>外部创建ContentView视图
  • 然后将ContentView传递给显示它的GenericView<Content: View>

但是:如果必须在GenericView<Content: View>内部创建ContentView,因为它需要一些仅在那里可用的参数,该怎么办?


示例:

  • UserView是通过提供用户ID创建的
  • UserView的视图模型使用ID获取用户名。因此创建UserView的用户只知道ID而不知道名称。该名称仅在UserView中可用
  • UserView在应用程序内的不同位置使用,甚至在不同的应用程序中使用。不同的地方需要以不同的布局/样式等显示用户名。为了不将所有布局硬编码为UserView,视图是通用的,并被赋予用于显示用户名的Content视图类型

编码

protocol NameView: View {
init(name: String)
}
struct NameOnlyView: NameView {
private let name: String

init(name: String) {
self.name = name
}

var body: some View {
Text(name)
}
}
struct NameGreetingView: NameView {
private let name: String

init(name: String) {
self.name = name
}

var body: some View {
Text("Hello (name)")
}
}
struct UserView<Content: NameView>: View {
private let name: String
private let nameView: Content

init(userId: Int, @ViewBuilder nameViewBuilder: (String) -> Content) {
name = LoadUserName(usingId: userId)
nameView = nameViewBuilder(name)
}

var body: some View {
nameView
}
}

struct SomeView: View {
var body: some View {
// What I would like to do
UserView(userId: 123, NameOnlyView)
UserView(userId: 987, NameGreetingView)
// What is required instead
UserView(userId: 123) {
NameOnlyView("Name which is not known here")
}
}
} 

当然,我可以移动逻辑,从给定的ID加载用户名,并使其在SomeView中可用。然而,这只是仅在UserView中可用但在SomeView中不可用的任何值的示例。特别是当在不同的应用程序中使用UserView时,我不想在UserView的所有可能的父视图中实现相同的逻辑来加载用户名(或其他(。

是否可以使用@ViewBuilder解决方案解决此问题

这能在SwiftUI中解决吗

还是我完全走错了路

看看SwiftUI的样式系统,例如ButtonStyle,博客文章Encapsulating SwiftUI视图样式(Swift by Sundell(有一些很棒的信息。希望你最终能得到这样的东西:

List {
UserView(userId: 987)
UserView(userId: 123)
}
.userViewStyle(.nameOnly)

最新更新