I have a video player in SwiftUI that is part of a subview and it is not at the top of the view hierarchy. The video player is inside of a scroll view with many other views. I would like to present this video in full screen when it is tapped. The link below is an example of the desired functionality. When the video is tapped it should resize to the full size of the screen and cover everything. I'm not sure how to do this since the video player is in a sub view.
example
https://drive.google.com/file/d/1fom7lDNjP7thxTuowYtsUXbErvX2jhzH/view?usp=sharing
This is an example from snapchat. Clicking the video animates it to full screen. When in full screen a drag gesture down animates it back to its normal size in the scroll view.
struct ContentView: View { //top of the view heiarchy
var body: some View {
SomeView()
}
}
struct SomeView: View {
let example = "example https://drive.google.com/file/d/1fom7lDNjP7thxTuowYtsUXbErvX2jhzH/view?usp=sharing"
var body: some View {
ScrollView {
//some views
VideoPlayerView(url: URL(string: example)!)
//some views
}
}
}
struct VideoPlayerView: View {
let url: URL
@State var player = AVPlayer(url: URL(string: "https://www.google.com")!)
@State var aspect: CGSize = CGSize(width: 16, height: 9)
var body: some View {
ZStack {
VideoPlayer(player: $player, showControls: false)
.aspectRatio(aspect, contentMode: .fit)
.onTapGesture {
//enter full screen from here while still playing from same duration
}
}
.onAppear {
player = AVPlayer(url: url)
Task {
do {
if let final = try await getVideoResolution(url: url.absoluteString) {
self.aspect = final
}
} catch { }
}
self.player.play()
}
}
}
func getVideoResolution(url: String) async throws -> CGSize? {
guard let track = try await AVURLAsset(url: URL(string: url)!).loadTracks(withMediaType: AVMediaType.video).first else { return nil }
let size = try await track.load(.naturalSize).applying(track.load(.preferredTransform))
return size
}
struct VideoPlayer : UIViewControllerRepresentable {
@Binding var player : AVPlayer
let showControls: Bool
func makeUIViewController(context: UIViewControllerRepresentableContext<VideoPlayer>) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.player = player
controller.showsPlaybackControls = showControls
controller.allowsVideoFrameAnalysis = false
return controller
}
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayer>) { }
}
Try this simple approach using a flag (
isfullScreen) to present a full screen inplace.Example code (with double tap):