Keep same UIViewControllerRepresentable between Swiftui Views without recreating it

154 views Asked by At

Initially I had a swiftui view:

MediaPlayerView : View {

   SwiftUIPlayer()

}

struct SwiftUIPlayer: UIViewControllerRepresentable {

func makeUIViewController(context: Context) -> MediaPlayerViewController {

this worked well. when orientation changes the UIViewControllerRepresentable remains unchanged and keeps playing the video.

i then created a landscape view and potrait view

eg.

LandscapeMediaPlayerView : View {
   SwiftUIPlayer()
}

PotraitMediaPlayerView : View {
   SwiftUIPlayer()
}


if isLandscape {
   LandscapeMediaPlayer()
} else {
   PotraitMediaPlayer()
}

this now recreates the SwiftUIPlayer and the underlying ViewController and AVPlayerViewcontrollers reset the video.

what is the best/easiest approach here? it will be a pain to have 1 Mediaplayer view that changes based on a passed in "isLandscape" bool.

having a singleton AVPlayer instance? this caused issues but should I just persevere with that?

2

There are 2 answers

1
mcritz On

Have you considered creating an object outside of a SwiftUI view and pass it in?

ParentView.swift

let PortraitView = PortraitView()
let ChildView = ChildView(portraitView: PortraitView)

var body: some View {
   ChildView
}

ChildView.swift

struct ChildView: View {
  let portraitView: PortraitView
  var body: some View {
      portraitView
  }
}
0
malhal On

You are in luck they added AnyLayout in iOS 16 to fix this exact problem!

Use an AnyLayout instance to enable dynamically changing the type of a layout container without destroying the state of the subviews. For example, you can create a layout that changes between horizontal and vertical layouts based on the current Dynamic Type setting:

struct DynamicLayoutExample: View {
    @Environment(\.dynamicTypeSize) var dynamicTypeSize


    var body: some View {
        let layout = dynamicTypeSize <= .medium ?
            AnyLayout(HStackLayout()) : AnyLayout(VStackLayout())


        layout {
            Text("First label")
            Text("Second label")
        }
    } } 

The types that you use with AnyLayout must conform to the Layout protocol. The above example chooses between the HStackLayout and VStackLayout types, which are versions of the built-in HStack and VStack containers that conform to the protocol. You can also use custom layout types that you define.