Standard UIKit views can be wrapped into SwiftUI views. Wrapping a Letterbox view into a UIViewRepresentable works, but only for the simplest cases where the player frame is known in advance (e.g. timeline never displayed and single aspect ratio supported).
If the player view boundaries need to be adjusted depending on the content, the view needs a delegate. For UIViewRepresentable, such delegates are implemented with a coordinator returned by the makeCoordinator() method. But this does not work for Letterbox layout updates, as they are initiated by the Letterbox view itself (with layout animations), which would need to be made alongside SwiftUI parent layout changes. This cannot be performed as a single common transaction and SwiftUI complains at runtime (Modifying state during view update, this will cause undefined behavior error). The result is ugly, of course.
For the moment, I therefore recommend the following approach:
For simple integrations as described above, a UIViewRepresentable wrapper works fine.
For more complex integrations, use a UIViewController subclass to manage the player, and wrap it into a UIViewControllerRepresentable. You are of course free to use SwiftUI to manage views around the player, but the player itself has to be handled in UIKit entirely.
Maybe SwiftUI will sometime provide a better way to communicate animated intrinsic size changes to the layout system, in which case a simpler approach will be possible (though the idea outlined above is quite simple in fact). For this reason, I am also not sure we should change how Letterbox view communicates frame changes to its parent. The current approach where animations are initiated by the view and communicated by delegation so that the parent view or controller can insert animations to be performed at the same time seems unavoidable to fulfil our requirements.
Standard UIKit views can be wrapped into SwiftUI views. Wrapping a Letterbox view into a
UIViewRepresentable
works, but only for the simplest cases where the player frame is known in advance (e.g. timeline never displayed and single aspect ratio supported).If the player view boundaries need to be adjusted depending on the content, the view needs a delegate. For
UIViewRepresentable
, such delegates are implemented with a coordinator returned by themakeCoordinator()
method. But this does not work for Letterbox layout updates, as they are initiated by the Letterbox view itself (with layout animations), which would need to be made alongside SwiftUI parent layout changes. This cannot be performed as a single common transaction and SwiftUI complains at runtime (Modifying state during view update, this will cause undefined behavior error). The result is ugly, of course.For the moment, I therefore recommend the following approach:
UIViewRepresentable
wrapper works fine.UIViewController
subclass to manage the player, and wrap it into aUIViewControllerRepresentable
. You are of course free to use SwiftUI to manage views around the player, but the player itself has to be handled in UIKit entirely.Maybe SwiftUI will sometime provide a better way to communicate animated intrinsic size changes to the layout system, in which case a simpler approach will be possible (though the idea outlined above is quite simple in fact). For this reason, I am also not sure we should change how Letterbox view communicates frame changes to its parent. The current approach where animations are initiated by the view and communicated by delegation so that the parent view or controller can insert animations to be performed at the same time seems unavoidable to fulfil our requirements.