问题描述
在 SwiftUI 中,您可以将多个视图作为一个参数传递给另一个视图,这要归功于 @viewbuilder
。每个子视图都被单独处理,因此在传递之后,可以包含在 vstack
、HStack
等中。
我的问题是:这个容器视图是否可以单独修改传递给它的每个子视图?例如,通过在每个子视图之间添加一个 Spacer
。
这是我正在寻找的等效功能:
struct SomeContainerView<Content: View> {
init(@viewbuilder content: @escaping () -> Content) {
self.content = content()
}
let content: Content
var body: some View {
HStack {
ForEach(content.childViews,id: \.id) { child in
// Give each child view a background
// Add a Spacer in between each child view
// Conditional formatting
// Etc.
}
}
}
}
我相信这是可能的,因为标准的 SwiftUI 容器视图可以影响传递给它们的子视图的外观和布局。除非这是通过 SwiftUI 的内部功能实现的?
解决这个问题的一种方法可能是传入多个视图参数而不是一个,尽管如果需要传递多个视图,这是不灵活和混乱的。一组视图似乎也没有意义,因为我在 SwiftUI 中的任何地方都没有注意到这种模式。
解决方法
根据我使用 @ViewBuilder 的个人经验,这是不可能的,当您将例如 Button 和 Text 以及 HStack 之类的传递给 SomeContainerView 时,它会将所有这些作为单个视图,如 VStack 或任何您命名的视图。并且任何修改都会发生在整个视图上,但是当您将 ForEach 传递给 SomeContainerView 时,事情会变得不同,在这种情况下,在发送 SomeContainerView 之前,您或多或少具有相同级别的控制,并且您可以根据需要修改每一行,但是它是有限的控制,例如,您无法再访问可以在 ForEach 中访问的索引或项目。 让我给你更多的光来看东西,即使你在 body 中工作我的意思是在 body 中运行一行代码后更高级别的观察和控制视图> 它不再是可编辑的,例如你有一个 Text 并且你给这个 Text 一个 backgroundColor,过了一段时间你想摆脱那个 Color,所以 SwiftUI 在给那个 bachgroundColor 后不再有控制权,那么它必须重新渲染/重新构建没有 backgroundColor 的文本来回答你的命令,这是 SwiftUI 和 UIKit-Swift 之间的巨大差异,一个视图就像一颗子弹,你无法抓住它或编辑它,你必须发射一个新的子弹到你想要的目标,所以再次回到你的问题,在你发送一个或一些视图到你的 SomeContainerView 之后,它几乎把它当作一个单一的视图。
但是如果你真的很想实现你想要的事情,那么你应该尝试其他的事情,比如一个 AnyView 数组可以解决你的问题,但你必须密切关注管理和控制这个数组。
,据我所知,你不能做这样的事情。但是您可以使用数组 View 并遍历该视图并修改您的子视图。
这是演示:
struct SomeModel<Content: View>: Identifiable {
var body: Content
var id = UUID()
}
public struct SomeContainerView<Content: View>: View {
let items: [SomeModel<Content>]
init(items: [SomeModel<Content>]) {
self.items = items
}
public var body: some View {
HStack {
ForEach(items.indices) { index in
items[index].body.background(index % 2 == 0 ? Color.red : Color.green)
}
}
}
}
struct TestSomeView: View {
var body: some View {
SomeContainerView(items: [.init(body: Text("Child_view_1")),.init(body: Text("Child_view_2")),.init(body: Text("Child_view_3"))])
}
}
,
一个更好的主意是让调用者决定如何在视图中布局内容,然后模型决定每个输入的数据。检查下面的代码-:
import SwiftUI
struct SomeContainerView<Content: View>:View {
var model:[Model] = []
init(model:[Model],@ViewBuilder content: @escaping (Model) -> Content) {
self.content = content
self.model = model
}
let content: (Model) -> Content
var body: some View {
VStack{
ForEach(model,id:\.id,content: content)
Spacer()
}
}
}
struct MainView:View {
@ObservedObject var modelData:objects
var body: some View{
SomeContainerView(model: modelData.myObj){ data in
Text(data.name)
.background(data.color)
}
}
}
struct Model{
var id = UUID().uuidString
var name:String
var color:Color
init(name:String,color:Color) {
self.name = name
self.color = color
}
}
class objects:ObservableObject,Identifiable{
var id = UUID().uuidString
@Published var myObj:[Model] = []
init() {
initModel()
}
func initModel(){
let model = Model(name: "Jack",color: .green)
let model1 = Model(name: "hey Jack",color: .red)
myObj.append(model)
myObj.append(model1)
}
}
@main -:
import SwiftUI
@main
struct WaveViewApp: App {
@StateObject var dataObj : objects
init() {
let obj = objects()
_dataObj = StateObject(wrappedValue: obj)
}
var body: some Scene {
WindowGroup {
MainView(modelData: dataObj)
}
}
}
输出-: