首页 > 解决方案 > 从另一个视图将变量传递给 SwiftUI AVPlayer

问题描述

这里的相对新手使用 SwiftUI 构建 iOS 应用程序。试图寻找解决方案,但没有运气。

在我的应用程序主屏幕(“HomeView.swift”)中,当用户选择他们想要播放的视频的缩略图时,该视频在网络上的绝对 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")!)

但是,当我尝试通过以下方式将变量值与 AVPlayer 一起使用时,Xcode 会出错:

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

这是错误消息:

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

我在这里包含了 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()
            }
    }
}

任何提示将非常感谢!

标签: iosswiftuiavplayer

解决方案


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

一种方法是使您的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变量。


推荐阅读