SwiftUI和AVPlayer

时间:2019-12-23 20:00:31

标签: swiftui

我正在尝试在我的SwiftUI界面中获取AVPlayer层。 Google在这个问题上没有很多答案,实际上,有一个教程看起来很有前途,请参见:https://medium.com/@chris.mash/avplayer-swiftui-b87af6d0553。但是这里充满了错误。因此,我尝试按照自己的方式进行操作。

计划:创建一个UIView子类,并向其中添加一个AVPlayerLayer,然后包装用于SwiftUI的UIView。

结果:什么都没有。

这是到目前为止我得到的:

struct PlayerView : UIViewRepresentable {

    func makeUIView(context: Context) -> UIView {
        return PlayerViewSwift()
    }

    func updateUIView(_ uiView: UIView, context: Context) {

    }
}

然后是PlayerViewSwift类:

class PlayerViewSwift : UIView {
   private let playerLayer = AVPlayerLayer()

    init() {
        super.init(frame: .infinite)


    }


    override init(frame: CGRect) {
      super.init(frame: frame)


    }



    // This attribute hides `init(coder:)` from subclasses
    @available(*, unavailable)
    required init?(coder aDecoder: NSCoder) {
        fatalError("NSCoding not supported")
    }

    override func layoutSubviews() {
         super.layoutSubviews()
      //  playerLayer.player =

        print("hmmm")

               let player = AVPlayer(url: URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u80")!)
               player.play()

               playerLayer.player = player
               layer.addSublayer(playerLayer)


     }


}

2 个答案:

答案 0 :(得分:0)

从URL路径扩展名中删除结尾的“ 0”,以使其为“ m3u8”而不是“ m3u80”。

另外,将playerLayer的帧设置为等于PlayerViewSwift末尾的layoutSubviews()的边界:

self.playerLayer.frame = self.bounds

答案 1 :(得分:0)

Swift 5.1,iOS 13。

我也阅读了Chris Mash教程[其中有4个],并将它们放在一起。我当然不记得他们到处都是bug,也许有一些错字。

它可以在SwiftUI导航控制器托管页面中播放嵌入式视频或流式视频。

import Foundation
import SwiftUI
import AVFoundation
import Combine

let timePublisher = PassthroughSubject<TimeInterval, Never>()
let videoFinished = PassthroughSubject<Void, Never>()
let nextFrame = PassthroughSubject<Void, Never>()

 struct PlayerTimeView: View {
 @State private var currentTime: TimeInterval = 0

var body: some View {
Text("\(currentTime)")
.onReceive(timePublisher) { time in
  self.currentTime = time
}.statusBar(hidden: true)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}

class PlayerUIView: UIView {
private var timeObservation: Any?
private let playerLayer = AVPlayerLayer()
override init(frame: CGRect) {
super.init(frame: .zero)
let url = Bundle.main.url(forResource: "AppDemo", withExtension: "mov")
//    let url = URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!
//    let url = URL(string: "https://www.youtube.com/watch?v=XK8METRgK_U")!
let player = AVPlayer(url: url!)
player.play()

  timeObservation = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 0.5, preferredTimescale: 600), queue: nil) { [weak self] time in
  guard let self = self else { return }
  // Publish the new player time
  print("time.seconds ", time.seconds)
  timePublisher.send(time.seconds)

  NotificationCenter.default.addObserver(self, selector: #selector(self.finishVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}

playerLayer.player = player
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
  super.layoutSubviews()
  playerLayer.frame = CGRect(x: 0, y: -115, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
 }

 @objc func finishVideo() {
    print("Video Finished")
      NotificationCenter.default.removeObserver(NSNotification.Name.AVPlayerItemDidPlayToEndTime)
     videoFinished.send()
     nextFrame.send()
  }

}

struct PlayerView: UIViewRepresentable {
 func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
 }
 func makeUIView(context: Context) -> UIView {
     PlayerUIView(frame: .zero)
 }
}

struct PlayerPage: View {
 @EnvironmentObject var env: MyAppEnvironmentData
 @Environment(\.presentationMode) var presentation

 var body: some View {
   VStack {
     PlayerView().onReceive(videoFinished) { (_) in
       self.presentation.wrappedValue.dismiss()
     }
   HStack {
     Spacer()
     PlayerTimeView()
     Spacer()
   }
  }
}
}