SwiftUI - 页面视图 - 传入不同的视图

5

我通过线程成功在SwiftUI中实现了PageView:
如何在SwiftUI中实现PageView?

通过一个数组传递多个视图非常方便,只要所有视图都是相同的结构体。
PageView([TestView(), TestView()]).
但是,我想传递不同的视图。
PageView([TestView(), AnotherView(), DifferentView()]).

所有的视图都是SwiftUI类型:
struct NAME : View { code }

当我尝试将不同的结构体添加到数组中时,会收到以下错误消息:

var pageViewViewArray = [TestView(), AnotherView(), DifferentView()]

异构集合文字字面量只能被推断为 '[Any]',如果这是有意的,请添加显式类型注释。
插入 'as [Any]'

通过将其转换为:

var pageViewViewArray = [TestView(), AnotherView(), DifferentView()] as! [Any]
PageView(pageViewViewArray)

PageView将会显示:

协议类型“Any”无法符合“View”的规定,因为只有具体的类型可以符合协议。

我非常感谢任何想法。

2个回答

8

尝试使用类型擦除,通过将每个视图强制转换为 AnyView

var pageViewViewArray: [AnyView] = [AnyView(TestView()), AnyView(AnotherView()), AnyView(DifferentView())]

文档在此,并且这里提供使用示例在此


1
这完美地解决了问题,甚至包括文档和示例。谢谢! - Peanutsmasher
1
只需记住AnyView很昂贵,因此只在绝对必要的时候使用它(在这种情况下是必要的)。 - Peter Schorn
@Peanutsmasher 这个解决方案会显著降低SwiftUI更新视图的效率。你可以(也应该)避免这种情况。请看下面我的答案。 - spafrou

1

有一种更高效的方法来完成它,不需要类型擦除。您应该创建一个共同的视图,在其中注入一个基于枚举值的值,然后返回所需的视图。请看下面的示例:

/// The first type of a view that accepts and shows a number
struct ViewA: View {

    let number: Int

    var body: some View {
        Text("\(number)")
    }
}

/// The second type of a view that accepts and shows a string
struct ViewB: View {

    let string: String

    var body: some View {
        Text(string)
    }
}

/// An enum type used for dependency injection
enum ViewType {

    case viewA(number: Int)
    case viewB(string: String)
}

/// A common view which internally handles different kind of views based on injected enum value
struct CommonView: View {

    let viewType: ViewType

    var body: some View {
        switch viewType {
        case .viewA(let number):
            ViewA(number: number)

        case .viewB(let string):
            ViewB(string: string)
        }
    }
}

// Views used for page view controller, that are now of same type:
var pageViewViewArray = [
    CommonView(viewType: .viewA(number: 1)),
    CommonView(viewType: .viewB(string: "Hello, World!"))
]

我不相信SwiftUI在我创建答案时允许使用switch或if语句,但这似乎有效!您介意告诉我为什么这种方法允许返回两种不同的视图类型(ViewA和ViewB),从而绕过“函数声明了一个不透明的返回类型,但其主体中的返回语句没有匹配的基础类型”这个通常出现的问题,如果我们尝试在主体中有条件地返回两种不同的视图类型? - RPatel99
函数构建器内的Switch语句是Swift 5.3的一部分。它之所以有效,是因为函数体实际上并不返回两种不同类型,而是返回以下类型:_ConditionalContent<ViewA, ViewB>。您可以使用以下代码进行检查:let view = CommonView(viewType: .viewA(number: 1)); print(type(of: view.body)) - spafrou
啊,明白了。那使用“if”语句返回不同的“View”为什么不起作用呢?我以为使用if语句也会返回“ConditionalContent”呢? - RPatel99
一个正常的函数内含if语句和一个@ViewBuilder函数之间有不同。前者返回两种不同的类型,因此代码无法编译。后者返回一个_CondtionalContent - spafrou

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