0

I am trying to show a looping video then allow the user to tap a button to show the next or previous looping video.

Why doesn't @Binding update this? and what is the right/best way to do this?

I am using a UIViewRepresentable. Here is my code...


struct Player: UIViewRepresentable {

    var videoFileNames: [String]
    @Binding var currentItem: Int

    func makeUIView(context: Context) -> UIView {
        return PlayerView(frame: .zero, videoFileNames: videoFileNames, currentItem: currentItem)
    }

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


class PlayerView: UIView {
    private let playerLayer = AVPlayerLayer()
    private var playerLooper: AVPlayerLooper?

    init(frame: CGRect, videoFileNames: [String], currentItem: Int) {
        super.init(frame: frame)

        var playerItems = [AVPlayerItem]()
        let player = AVQueuePlayer(items: playerItems)

        for videoFileName in videoFileNames {
            guard let path = Bundle.main.path(forResource: videoFileName, ofType: "mp4") else {
                return
            }
            let videoURL = NSURL(fileURLWithPath: path)
            let playerItem = AVPlayerItem(url: videoURL as URL)
            playerItems.append(playerItem)
        }

        playerLooper = AVPlayerLooper(player: player, templateItem: playerItems[currentItem])

        player.volume = 0
        player.play()

        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspectFill 

        layer.addSublayer(playerLayer)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
}
Dan
  • 543
  • 2
  • 13

1 Answers1

0

Change in @Binding result in call updateUIView only, so you need to adapt something like below (in pseudo code, scratchy)

struct Player: UIViewRepresentable {

    var videoFileNames: [String]
    @Binding var currentItem: Int

    private var playerView: PlayerView!

    func makeUIView(context: Context) -> UIView {
        let view = PlayerView(frame: .zero, videoFileNames: videoFileNames, currentItem: currentItem)
        self.playerView = view
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
        self.playerView.currentItem = currentItem // update player !!
    }
}

class PlayerView: UIView {
   var currentItem: Int {
       didSet {
          // .. refresh here internal player
       }
   }

    init(frame: CGRect, videoFileNames: [String], currentItem: Int) {
        super.init(frame: frame)

        self.currentItem = currentItem
        var playerItems = [AVPlayerItem]()

   // .. other code

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Thanks @Asperi I was able to get the player to update but now I'm having issues with the looping. Do you think this is the best approach for switching between videos? – Dan Jun 03 '20 at 18:25