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

问题描述 投票:0回答:4

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

我在 SwiftUI 中成功运行了 VideoPlayer。

我使用以下代码调用播放器视图:

VideoPlayer(player: AVPlayer(url: url))

问题在于,只要 VideoPlayer 的父视图更新(即重新渲染),视频就会停止播放。

由于在 SwiftUI 中我无法控制何时发生这样的重新渲染时刻,所以我不知道如何克服这个问题。

有什么想法吗?

这是完整的代码:

VideoPlayer View 的调用方式如下:

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

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

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")
                }
            }
        }
    }
}
swift swiftui video-player childviews view-hierarchy
4个回答
2
投票

使用@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)
        }
    }
}

有了这些,就足以像这样调用 CustomPlayerVideo 了:

CustomPlayerView(url: url)

备注:我需要在 CustomPlayerView 中使用

ZStack
而不是
Group
才能使其正常工作。


0
投票

这是对我们对另一个答案的评论线程的回应:

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

我不确定这是否确实更好,所以值得测试。但是,它确实控制了

AVPlayer
的创建时间,并避免在父级的每次渲染上重新创建
PlayerViewModel


0
投票

我找到了解决办法。

拨打以下电话:

CustomPlayerView(url: url)

...而不是:

VideoPlayer(player: AVPlayer(url: url))

不知道为什么这有效,很难。

也许有人可以进一步解释?

这是自定义视频播放器代码:

struct CustomPlayerView: View {

    private let url: URL

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

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

通过这个微小的更改,即使父视图重新渲染,视频也会继续播放。还是不知道为什么???

---------- 用@jnpdx 的提示回答 --------

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

0
投票

我已经完成了已接受答案的简化版本,不需要视图模型。

private struct CustomPlayerView: View {
    @State private var avPlayer: AVPlayer
    
    init(url: URL) {
        _avPlayer = State(initialValue: AVPlayer(url: url))
    }

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

可以以同样的方式使用。

© www.soinside.com 2019 - 2024. All rights reserved.