swiftswiftuivideo-playerchildviewsview-hierarchy

VideoPlayer in SwiftUI stops playing when parent-View updates


Using Swift5.3.2, iOS14.4.1, Xcode 12.4,

I am successfully running a VideoPlayer in SwiftUI.

I am calling the Player view with this code: VideoPlayer(player: AVPlayer(url: url)).

The problem is that the video stops playing whenever a parent-View of the VideoPlayer updates (i.e. re-renders).

Since in SwiftUI I don't have any control over when such a re-render moment takes place, I don't know how to overcome this problem.

Any ideas ?

Here is the entire Code:

The VideoPlayer View is called as such:

struct MediaTabView: View {
    
    @State private var url: URL
    
    var body: some View {
        
        // CALL TO VIDEOPLAYER IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        VideoPlayer(player: AVPlayer(url: url))
    }
}

The MediaTabView is called as such:

import SwiftUI

struct PageViewiOS: View {
    
    var body: some View {
        
        ZStack {
            
            Color.black
            
            // CALL TO MEDIATABVIEW IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!d
            MediaTabView(url: URL(string: "https://someurel.com"))
                
            CloseButtonView()
        }
    }
}

The PageViewiOS View is called as such:

struct MainView: View {
    
    @EnvironmentObject var someState: AppStateService
    
    var body: some View {
        NavigationView {
            Group {                                                    
                if someState = .stateOne {

                    // CALL TO PAGEVIEWIOS IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    PageViewiOS()
                } else {
                    Text("hello")
                }
            }
        }
    }
}

Solution

  • This is in response to our comment thread on the other answer:

    class PlayerViewModel: ObservableObject {
        
        @Published var avPlayer: AVPlayer?
        
        func loadFromUrl(url: URL) {
            avPlayer = AVPlayer(url: url)
        }
    }
    
    struct CustomPlayerView: View {
        
        var url : URL
        @StateObject private var playerViewModel = PlayerViewModel()
    
        var body: some View {
            ZStack {
                if let avPlayer = playerViewModel.avPlayer {
                    VideoPlayer(player: avPlayer)
                }
            }.onAppear {
                playerViewModel.loadFromUrl(url: url)
            }
        }
    }
    

    I'm not sure that this is definitively better, so it's worth testing. But, it does control when AVPlayer gets created and avoids re-creating PlayerViewModel on every render of the parent as well.