Ios 如何使用SwiftUI创建动态视图列表

Ios 如何使用SwiftUI创建动态视图列表,ios,swift,swiftui,Ios,Swift,Swiftui,我可以做一个静态列表,比如 List { View1() View2() } 但是如何从数组中生成元素的动态列表呢? 我尝试了以下操作,但出现错误:包含控制流语句的闭包不能与函数生成器“ViewBuilder”一起使用。 let elements: [Any] = [View1.self, View2.self] List { ForEach(0..<elements.count) { index in if let _ =

我可以做一个静态列表,比如

List {
   View1()
   View2()
}
但是如何从数组中生成元素的动态列表呢? 我尝试了以下操作,但出现错误:包含控制流语句的闭包不能与函数生成器“ViewBuilder”一起使用。

    let elements: [Any] = [View1.self, View2.self]

    List {
       ForEach(0..<elements.count) { index in
          if let _ = elements[index] as? View1 {
             View1()
          } else {
             View2()
          }
    }
}
let元素:[Any]=[View1.self,View2.self]
名单{

ForEach(0..
if/let
流控制语句不能在
@ViewBuilder
块中使用

这些特殊块中的流控制语句被转换为结构

e、 g

if(someBool){
视图1()
}否则{
视图2()
}
转换为
条件值

并非所有的流量控制语句都在这些块中可用,即
开关
,但这在将来可能会改变

更多关于这方面的信息,请参阅


在您的特定示例中,您可以按如下方式重写代码:

struct ContentView:View{
let元素:[Any]=[View1.self,View2.self]
var body:一些观点{
名单{

ForEach(0..是否可以根据需要返回不同的
视图?

简而言之:有点像

如中所述,不可能有多个类型返回为不透明类型

如果具有不透明返回类型的函数从多个位置返回,则所有可能的返回值必须具有相同的类型。对于泛型函数,该返回类型可以使用该函数的泛型类型参数,但它必须仍然是单个类型

那么当静态地传递一些不同的视图时,
List
如何做到这一点呢?

列表没有返回不同的类型,它返回的
EmptyView
中填充了一些内容视图。构建器可以围绕您传递给它的任何类型的视图构建包装器,但当您使用越来越多的视图时,它甚至不会编译!(例如,尝试传递10个以上的视图,看看会发生什么)

如您所见,
List
内容是某种类型的
ListCoreCellHost
,包含一个子集视图,证明它只是它所表示内容的容器

如果我有很多数据(如联系人)并想填写一个列表怎么办?

您可以遵守
identified
或使用
identified(by:)
功能,如前所述

如果任何联系人可能有不同的看法怎么办?

您称之为“联系”,这意味着它们是相同的东西!您应该考虑OOP使它们相同,并使用<代码>继承< /代码>优点。但是不同于<代码> UIKit < /代码>, SWIFTUI基于Struts。它们不能相互继承。

那么解决方案是什么?

必须将要显示的所有类型的视图包装到一个
视图
类型中。
EmptyView
的文档不足以利用这一点(目前)。但是!!!幸运的是,您可以使用UIKit

我如何利用
UIKit
进行此操作

  • UIKit
    上执行
    View1
    View2
  • 使用UIKit定义一个
    ContainerView
  • 实现
    ContainerView
    的方法是采用参数并表示
    View1
    View2
    和适合的大小
  • 符合
    UIViewRepresentable
    并实施其要求
  • 制作您的SwiftUI
    列表
    以显示
    容器视图的列表
    所以现在它是一种可以表示多个视图的单一类型

您可以使用动态子视图列表,但需要注意类型和实例化。这里是动态“汉堡”的演示,仅供参考

//选择当前页面的页面视图
///这可以重构到顶层
结构页面:视图{
@绑定变量currentPage:Int
var pageArray:[任何视图]
变量主体:AnyView{
返回页面数组[currentPage]
}
}
//顶层视图
///创建两个子视图,关键是需要将它们转换为AnyView()结构
///Pages视图然后根据当前页面状态动态显示子视图
结构ContentView:View{
@状态变量currentPage:Int=0
设page0=AnyView(
导航视图{
VStack{
文本(“页面菜单”)。颜色(.black)
列表([“1”、“2”、“3”、“4”、“5”])。由“\.self”标识,{中的行
文本(行)
}.navigationBarTitle(文本(“页面”),显示模式:。大)
}
}
)
让page1=AnyView(
导航视图{
VStack{
文本(“另一页菜单”)。颜色(.black)
列表([“A”、“B”、“C”、“D”、“E”])。由:\.self)标识{中的行
文本(行)
}.navigationBarTitle(文本(“第二页”),显示模式:。大)
}
}
)
var body:一些观点{
让pageArray:[AnyView]=[page0,page1]
返回页面(currentPage:self.$currentPage,pageArray:pageArray)
}
}

看起来答案与将我的视图包装到
AnyView

struct ContentView : View {
    var myTypes: [Any] = [View1.self, View2.self]
    var body: some View {
        List {
            ForEach(0..<myTypes.count) { index in
                self.buildView(types: self.myTypes, index: index)
            }
        }
    }
    
    func buildView(types: [Any], index: Int) -> AnyView {
        switch types[index].self {
           case is View1.Type: return AnyView( View1() )
           case is View2.Type: return AnyView( View2() )
           default: return AnyView(EmptyView())
        }
    }
}
struct ContentView:View{
var myTypes:[Any]=[View1.self,View2.self]
var body:一些观点{
名单{
ForEach(0..AnyView{
开关类型[索引].self{
大小写为View1。类型:returnanyview(View1())
大小写为View2。类型:returnanyview(View2())
默认值:返回AnyView(EmptyView())
}
}
}

有了这个,我现在可以从服务器获取视图数据并合成它们。而且,它们只在需要时才实例化。

我还想在同一个列表中使用不同的视图,因此实现了一个高级的li
struct MyImageView: View, Identifiable {
    // Conform to Identifiable:
    var id = UUID()
    // Name of the image:
    var imageName: String

    var body: some View {
        Image(imageName)
            .resizable()
            .frame(width: 50, height: 50)
    }
}
// Images:
HStack(spacing: 10) {
    ForEach(images, id: \.self) { imageName in
        MyImageView(imageName: imageName)
    }
    Spacer()
}
struct View1: View {
    var body: some View {
        Text("View1")
    }
}

struct View2: View {
    var body: some View {
        Text("View2")
    }
}

class ViewBase: Identifiable {
    func showView() -> AnyView {
        AnyView(EmptyView())
    }
}

class AnyView1: ViewBase {
    override func showView() -> AnyView {
        AnyView(View1())
    }
}

class AnyView2: ViewBase {
    override func showView() -> AnyView {
        AnyView(View2())
    }
}

struct ContentView: View {
    let views: [ViewBase] = [
        AnyView1(),
        AnyView2()
    ]

    var body: some View {
        List(self.views) { view in
            view.showView()
        }
    }
}
struct ContentView: View {
    let elements: [Any] = [View1.self, View2.self]

    var body: some View {
        List {
            ForEach(0 ..< elements.count) { index in
                if let _ = elements[index] as? View1 {
                    View1()
                } else {
                    View2()
                }
            }
        }
    }
}
@ViewBuilder
func buildView(types: [Any], index: Int) -> some View {
    switch types[index].self {
    case is View1.Type: View1()
    case is View2.Type: View2()
    default: EmptyView()
    }
}
struct AMZ1: View {
    var body: some View {         
       Text("Text")     
    }
 }

struct PageView: View {
    
   let elements: [Any] = [AMZ1(), AMZ2(), AMZ3()]
    
   var body: some View {
     TabView {
       ForEach(0..<elements.count) { index in
         if self.elements[index] is AMZ1 {
             AMZ1()
           } else if self.elements[index] is AMZ2 {
             AMZ2()
           } else {
             AMZ3()
      }
   }
}