简体   繁体   English

SwiftUI 中的 VideoPlayer 在父视图更新时停止播放

[英]VideoPlayer in SwiftUI stops playing when parent-View updates

Using Swift5.3.2, iOS14.4.1, Xcode 12.4,使用 Swift5.3.2、iOS14.4.1、Xcode 12.4、

I am successfully running a VideoPlayer in SwiftUI.我在 SwiftUI 中成功运行了 VideoPlayer。

I am calling the Player view with this code: VideoPlayer(player: AVPlayer(url: url)) .我使用以下代码调用播放器视图: VideoPlayer(player: AVPlayer(url: url))

The problem is that the video stops playing whenever a parent-View of the VideoPlayer updates (ie re-renders).问题是,只要 VideoPlayer 的父视图更新(即重新渲染),视频就会停止播放。

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.由于在 SwiftUI 中我无法控制何时发生这种重新渲染时刻,我不知道如何克服这个问题。

Any ideas?有任何想法吗?

Here is the entire Code:这是整个代码:

The VideoPlayer View is called as such: VideoPlayer 视图是这样调用的:

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: MediaTabView 是这样调用的:

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: PageViewiOS 视图是这样调用的:

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")
                }
            }
        }
    }
}

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.但是,它确实控制何时创建AVPlayer ,并避免在每次渲染父级时重新创建PlayerViewModel

I have found a solution.我找到了解决方案。

Call the following:调用以下命令:

CustomPlayerView(url: url)

...instead of: ...代替:

VideoPlayer(player: AVPlayer(url: url))

Not sure why this works, tough.不知道为什么这有效,很难。

Maybe somebody can explain further?也许有人可以进一步解释?

Here is the CustomVideoPlayer code:这是 CustomVideoPlayer 代码:

struct CustomPlayerView: View {

    private let url: URL

    init(url: URL) {
        self.url = url
    }

    var body: some View {
        VideoPlayer(player: AVPlayer(url: url))
    }
}

With this minor change, the Video keeps on playing even tough the parent-View gets re-rendered.通过这个微小的变化,视频继续播放,即使父视图重新渲染也很困难。 Still, not sure why???还是不知道为什么???

----------- Answer with the hint of @jnpdx -------- ------------ 用@jnpdx 的提示回答--------

I changed the CustomVideoPlayer even more:我进一步更改了 CustomVideoPlayer:

CustomPlayerView(playerViewModel: PlayerViewModel(avPlayer: AVPlayer(url: url)))
import SwiftUI
import AVKit

class PlayerViewModel: ObservableObject {
    
    @Published var avPlayer: AVPlayer
    
    init(avPlayer: AVPlayer) {
        self.avPlayer = avPlayer
    }
}

struct CustomPlayerView: View {
    
    @StateObject var playerViewModel: PlayerViewModel

    var body: some View {
        VideoPlayer(player: playerViewModel.avPlayer)
    }
}

With the solution from @jnpdx, everything works now.使用@jnpdx 的解决方案,现在一切正常。

Here is the final solution (full credit to @jnpdx):这是最终的解决方案(完全归功于@jnpdx):

import SwiftUI
import AVKit

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)
        }
    }
}

With that in hand, it is enough to call the CustomPlayerVideo like that:有了这些,像这样调用 CustomPlayerVideo 就足够了:

CustomPlayerView(url: url)

Remark: I needed to use ZStack instead of Group in my CustomPlayerView in order for it to work.备注:我需要在 CustomPlayerView 中使用ZStack而不是Group才能使其工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM