【问题标题】:How to manage AVPlayer state in SwiftUI如何在 SwiftUI 中管理 AVPlayer 状态
【发布时间】:2020-12-03 18:34:05
【问题描述】:

我有一个 SwiftUI 中的 URL 列表。当我点击一个项目时,我会呈现一个全屏视频播放器。我有一个@EnvironmentObject 可以处理一些查看器选项(例如,是否显示时间码)。我还有一个显示和隐藏时间码的切换开关(我只在此示例中包含切换,因为时间码视图无关紧要)但每次我更改切换时,都会再次创建视图,这会重新设置 @ 987654323@。这是有道理的,因为我在视图的初始化程序中创建了播放器。

我想创建自己的 ObserveredObject 类来包含 AVPlayer 但我不确定如何或在哪里初始化它,因为我需要给它一个 URL,我只能从初始化器中知道CustomPlayerView。我还考虑过将播放器设置为@EnvironmentObject,但初始化一些我可能不需要的东西似乎很奇怪(如果用户没有点击 URL 来启动播放器)。

请问创建AVPlayer 交给AVKit 的VideoPlayer 的正确方法是什么?这是我的示例代码:

class ViewerOptions: ObservableObject {
    @Published var showTimecode = false
}

struct CustomPlayerView: View {
    
    @EnvironmentObject var viewerOptions: ViewerOptions
    
    private let avPlayer: AVPlayer
    
    init(url: URL) {
        avPlayer = AVPlayer(url: url)
    }
    
    var body: some View {
        HStack {
            VideoPlayer(player: avPlayer)
            Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
        }
    }
}

【问题讨论】:

标签: ios swiftui avfoundation avkit


【解决方案1】:

您可以在这里采取几种方法。您可以尝试一下,看看哪一种最适合您。

选项 1:正如您所说,您可以将 avPlayer 包装在一个新的 ObserveredObject 类中

class PlayerViewModel: ObservableObject {
    @Published var avPlayer: AVPlayer? = nil
}

class ViewerOptions: ObservableObject {
    @Published var showTimecode = false
}


@main
struct DemoApp: App {
    var playerViewModel = PlayerViewModel()
    var viewerOptions = ViewerOptions()

    var body: some Scene {
        WindowGroup {
            CustomPlayerView(url: URL(string: "Your URL here")!)
                .environmentObject(playerViewModel)
                .environmentObject(viewerOptions)
        }
    }
}

struct CustomPlayerView: View {
    @EnvironmentObject var viewerOptions: ViewerOptions
    @EnvironmentObject var playerViewModel: PlayerViewModel

    init(url: URL) {
        if playerViewModel.avPlayer == nil {
            playerViewModel.avPlayer = AVPlayer(url: url)
        } else {
            playerViewModel.avPlayer?.pause()
            playerViewModel.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
        }
    }

    var body: some View {
        HStack {
            VideoPlayer(player: playerViewModel.avPlayer)
            Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
        }
    }
}

选项 2:您可以将 avPlayer 作为可选属性添加到现有的类 ViewerOptions 中,然后在需要时对其进行初始化

class ViewerOptions: ObservableObject {
    @Published var showTimecode = false
    @Published var avPlayer: AVPlayer? = nil
}

struct CustomPlayerView: View {

    @EnvironmentObject var viewerOptions: ViewerOptions

    init(url: URL) {
        if viewerOptions.avPlayer == nil {
            viewerOptions.avPlayer = AVPlayer(url: url)
        } else {
            viewerOptions.avPlayer?.pause()
            viewerOptions.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
        }
    }

    var body: some View {
        HStack {
            VideoPlayer(player: viewerOptions.avPlayer)
            Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
        }
    }
}

选项 3:将您的 avPlayer 设置为状态对象,这样它的内存将由系统管理,并且在您的视图存在之前,它不会重新设置它并为您保持活动状态。

class ViewerOptions: ObservableObject {
    @Published var showTimecode = false
}

struct CustomPlayerView: View {

    @EnvironmentObject var viewerOptions: ViewerOptions
    @State private var avPlayer: AVPlayer

    init(url: URL) {
        _avPlayer = .init(wrappedValue: AVPlayer(url: url))
    }

    var body: some View {
        HStack {
            VideoPlayer(player: avPlayer)
            Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
        }
    }
}

选项 4:在需要时创建您的 avPlayer 对象并忘记它(不确定这是否是您的最佳方法,但如果您不需要播放器对象执行自定义操作,则可以使用此选项)

class ViewerOptions: ObservableObject {
    @Published var showTimecode = false
}

struct CustomPlayerView: View {

    @EnvironmentObject var viewerOptions: ViewerOptions
    private let url: URL

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

    var body: some View {
        HStack {
            VideoPlayer(player: AVPlayer(url: url))
            Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
        }
    }
}

【讨论】:

  • 太棒了,谢谢 - 我这周不在,所以无法测试它,但这是非常详细的,看起来它会完全符合我的要求。谢谢!
  • 如果我们要使用 iOS 13 怎么办?因为iOS 14+支持这个答案
猜你喜欢
  • 1970-01-01
  • 2011-02-08
  • 2020-06-16
  • 1970-01-01
  • 2020-03-05
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多