4

I noticed that you can only have a single .popover modifier in SwiftUI. I have to present two possible simple popovers, one of them a MenuView, the other a CreateChannelView.

For that I have:

@State private var popover: some View
@State private var showPopover = false

and then the modifier:

.popover(isPresented: self.$showPopover) {
    self.popover
}

The problem is that I don't see how can I assign instances of MenuView or CreateChannelView to popover as I get the error:

Cannot assign value of type 'MenuView' to type 'some View'

This is a little bit different than this question which passes generic views in the init method.

Rivera
  • 10,792
  • 3
  • 58
  • 102
  • 1
    some View - means one concrete type that conforms to View co it cannot once be MenuView and other time be CreateChannelView. – LuLuGaGa Oct 21 '19 at 20:48

2 Answers2

8

The solution was to use AnyView:

@State private var popover: AnyView

Then it can be assigned as:

self.popover = AnyView(CreateChannelView(showing: self.$showPopover))
Rivera
  • 10,792
  • 3
  • 58
  • 102
0

You can declare the two views as two different variables and then toggle selection between them with a boolean that determines which is presented. I made an example program with the information you gave me:

struct ContentView: View {
    let buttonSize: CGFloat = 30
    @State var isPresented = false
    @State var usePopover1 = true
    var popover1: some View {
        Text("Popover 1")
    }
    var popover2: some View {
        Image(systemName: "star")
    }
    var body: some View {
        VStack {
            Button(action: {
                self.isPresented = true
            }) {
                Text("Present popover")
            }
            Button(action: {
                self.usePopover1.toggle()
            }) {
                Text("Switch from \(self.usePopover1 ? "popover1" : "popover2") to \(self.usePopover1 ? "popover2" : "popover1")")
            }
        }.popover(isPresented: $isPresented) {
            if self.usePopover1 {
                AnyView(self.popover1)
            } else {
                AnyView(self.popover2)
            }
        }
    }
}

I just made the two popovers on the spot for demonstration purposes, but you can declare yours as being the two different types you mentioned in your question (let popover1: MenuView = MenuView(...) and let popover2: CreateChannelView = CreateChannelView(...)).

RPatel99
  • 7,448
  • 2
  • 37
  • 45
  • Can you share some reading about this? Because it looks so strange that you define `some views` and then you have to wrap them in any views… – Uko Aug 09 '22 at 07:17
  • `some View` specifies that the popovers will be, as the syntax suggests, some type of view, however they retain their original typing. `popover1` is still a `Text` and `popover2` is still an `Image`. The `.popover` requires that the closure returns a uniform type, and since `popover1` and `popover2` are different types, we wrap both in `AnyView`. – RPatel99 Sep 08 '22 at 14:42