Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - PageView - Pass in different Views

I successfully implemented PageView within SwiftUI via thread:
How to implement PageView in SwiftUI?

Passing in multiple Views via an Array works like a charm, as long as all views are of the same struct.
PageView([TestView(), TestView()]).
However, I'd like to pass in different views.
PageView([TestView(), AnotherView(), DifferentView()]).

All views are of SwiftUI type:
struct NAME : View { code }

When I try to add different structs to an array I get the following error message:

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

Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional.
Insert' as [Any]

By casting it to:

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

PageView will say:

Protocol type 'Any' cannot conform to 'View' because only concrete types can conform to protocols

I'll greatly appreciate any ideas.

like image 294
Peanutsmasher Avatar asked Oct 21 '19 13:10

Peanutsmasher


2 Answers

Try using type erasure by casting every view to AnyView:

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

Documentation here, and an example of using it here.

like image 143
RPatel99 Avatar answered Sep 19 '22 09:09

RPatel99


There is a more efficient way to do it, without type erasure. You should create a common view in which you inject an enum value based on which you then return a desired view. Take a look at an example below:

/// 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!"))
]
like image 31
spafrou Avatar answered Sep 20 '22 09:09

spafrou