从另一个视图将变量传递给 SwiftUI AVPlayer

Pass variable to SwiftUI AVPlayer from another view

这里是使用 SwiftUI 构建 iOS 应用程序的相对新手。尝试寻找解决方案但没有成功。

在我的应用程序主屏幕(“HomeView.swift”)中,当用户 select 他们想要播放的视频的缩略图时,该视频在网络上的绝对 URL (从本地 .json 文件中检索到的)在变量(“videoLink”)中传递给视频播放器视图(“VideoPlayer.swift”)。

现在,Xcode 可以让我成功呈现 videoLink 变量的值(如果只显示为文本),如下所示:

Text("\(videoLink)")

它允许硬编码 URL 与 AVPlayer 一起使用,如下所示:

let player = AVPlayer(url: URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!)

然而,Xcode 当我尝试以下列方式使用 AVPlayer 的变量值时出现错误:

let player = AVPlayer(url: URL(string: "\(videoLink)")!)

错误信息如下:

“不能在 属性 初始化器中使用实例成员 'videoLink';属性 初始化器 运行 在 'self' 可用之前。”。 =33=]

我在此处包含 VideoPlayer.swift 视图的完整代码。

import SwiftUI
import AVKit

struct PlayerView: View {
    
    @ObservedObject var model = VideoModel()
    
    var videoLink = ""

    let player = AVPlayer(url: URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!)

    var body: some View {

        VideoPlayer(player: player) {
            VStack {
                Text("\(videoLink)")
                    .foregroundColor(.white)
                Spacer()
            }
        }
            .onAppear() {
                player.play()
            }
            .onDisappear() {
                player.pause()
            }
    }
}

如有任何提示,我们将不胜感激!

有几种方法可以解决这个问题。

一种方法是让你的 player 变量成为一个可选的 @State 变量,并在 onAppear:

中设置它的值
struct PlayerView: View {
    
    @ObservedObject var model = VideoModel()
    
    var videoLink : String
    
    @State private var player : AVPlayer?
    
    var body: some View {
        
        VideoPlayer(player: player) {
            VStack {
                Text("\(videoLink)")
                    .foregroundColor(.white)
                Spacer()
            }
        }
        .onAppear() {
            guard let url = URL(string: videoLink) else {
                return
            }
            player = AVPlayer(url: url)
            player?.play()
        }
        .onDisappear() {
            player?.pause()
        }
    }
}

另一种选择(我不太喜欢)是将玩家作为参数传入:

struct PlayerView: View {
    
    @ObservedObject var model = VideoModel()
    
    var videoLink : String
    var player : AVPlayer
    
    var body: some View {
        
        VideoPlayer(player: player) {
            VStack {
                Text("\(videoLink)")
                    .foregroundColor(.white)
                Spacer()
            }
        }
        .onAppear() {
            player.play()
        }
        .onDisappear() {
            player.pause()
        }
    }
}

并这样称呼它:

PlayerView(videoLink: "url", player: AVPlayer(url: url))

我更喜欢第一种方法的一个原因是,在第二种选择中,如果父视图被重新渲染,它也会重新实例化AVPlayer,而在第一种选择中,繁重的工作在 onAppear 中完成,然后使用 @State 变量保留在渲染之间。