简体   繁体   English

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

[英]Pass variable to SwiftUI AVPlayer from another view

Relative newbie here building iOS app using SwiftUI.这里的相对新手使用 SwiftUI 构建 iOS 应用程序。 Tried searching for a solution but no luck.试图寻找解决方案,但没有运气。

From my app home screen ("HomeView.swift"), when users select a thumbnail image of the video they want to play, the video's absolute URL on the web (which is retrieved from a local.json file) gets passed in the variable ("videoLink") to the video player view ("VideoPlayer.swift"). From my app home screen ("HomeView.swift"), when users select a thumbnail image of the video they want to play, the video's absolute URL on the web (which is retrieved from a local.json file) gets passed in the variable ("videoLink") 到视频播放器视图 ("VideoPlayer.swift")。

Right now, Xcode lets me successfully render the value of the videoLink variable if displayed simply as text, as in this:现在,如果简单地显示为文本,Xcode 可以让我成功渲染 videoLink 变量的值,如下所示:

Text("\(videoLink)")

And it allows a hard-coded URL to be used with AVPlayer, as in this:它允许硬编码的 URL 与 AVPlayer 一起使用,如下所示:

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

However, Xcode gives an error when I try to use the variable value with AVPlayer in the following way:但是,当我尝试按以下方式将变量值与 AVPlayer 一起使用时,Xcode 会出错:

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

Here's the error message:这是错误消息:

"Cannot use instance member 'videoLink' within property initializer; property initializers run before 'self' is available." “不能在属性初始化程序中使用实例成员 'videoLink';属性初始化程序在 'self' 可用之前运行。”

I'm including the complete code for the VideoPlayer.swift view here.我在这里包含了 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()
            }
    }
}

Any tips would be greatly appreciated!任何提示将非常感谢!

There are a few ways to approach this.有几种方法可以解决这个问题。

One way is to make your player variable an optional @State variable and set its value inside onAppear :一种方法是让你的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()
        }
    }
}

Another option (which I don't like quite as much) is to pass the player in as a parameter:另一种选择(我不太喜欢)是将播放器作为参数传递:

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

and call it like:并称之为:

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

One reason that I like the first method better is that in the 2nd option, if the parent view were re-rendered, it would also re-instantiate the AVPlayer , whereas in the first option, the heavy lifting is done in onAppear and then kept between renders with the @State variable.我更喜欢第一种方法的一个原因是,在第二个选项中,如果父视图被重新渲染,它也会重新实例化AVPlayer ,而在第一个选项中,繁重的工作在onAppear中完成,然后保持在使用@State变量的渲染之间。

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

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