【问题标题】:Draw button on top of AVPlayerAVPlayer 顶部的绘制按钮
【发布时间】:2016-07-21 23:44:00
【问题描述】:

我必须在视频 relay next previous , leave comment 上绘制一个标签或按钮。视频列表有它,一旦用户从表格中选择一个项目,它需要播放,一旦播放器播放完成,这些按钮或标签应该出现在视频顶部

这是我的代码:

comPlayerControl = AVPlayerViewController()

if let player = comPlayerControl {

    let videoURL: String = "http://cdnapi.kaltura.com/p/11/sp/11/playManifest/entryId/"+selectedSubmission.transcodeRefId+"/format/applehttp/protocol/http/a.m3u8"
    let playerItem = AVPlayerItem(URL: NSURL(string: videoURL)! )
    commmentPlayer = AVPlayer(playerItem: playerItem)
    player.player = commmentPlayer
    player.view.frame = videoCell.frame
    player.view.sizeToFit()

    player.showsPlaybackControls = true
    NSNotificationCenter.defaultCenter().addObserver(
        self, 
        selector: #selector(CommentsTableViewController.playerDidFinishPlaying(_:)),
        name: AVPlayerItemDidPlayToEndTimeNotification, 
        object: playerItem
    )

    comPlayerControl.delegate = self
    videoCell.addSubview(player.view)
}

func playerDidFinishPlaying(note: NSNotification) {
    print("Video Finished")
    let DynamicView=UIView(frame: CGRectMake(100, 200, 100, 100))
    DynamicView.backgroundColor=UIColor.greenColor()
    DynamicView.layer.cornerRadius=25
    DynamicView.layer.borderWidth=2
    DynamicView.layer.zPosition = 1;
    comPlayerControl.view.addSubview(DynamicView)
}

这样的要求

【问题讨论】:

  • 你可以从这里的项目中轻松地做到这一点:stackoverflow.com/a/36389738/1151916 只需要在 xib 文件中添加自定义按钮和标签,它们就会呈现给用户。你想要什么功能?

标签: ios swift avfoundation avplayer avplayerviewcontroller


【解决方案1】:

我认为制作 avplayer 按钮的最佳方法在这里解释:IOS 8 Video Playback using AVPlayer and AVPlayerViewController

所以,我更喜欢并同意这些说明,但如果您仍然想要 添加这些按钮你可以尝试将它们添加到self.window中

if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {
        let myFirstButton = UIButton()
        myFirstButton.setTitle("test", forState: .Normal)
        window.addSubview(myFirstButton)
        ...
}

【讨论】:

    【解决方案2】:

    您使用的是AVPlayerViewController,因此没有理由像 Alessandro Ornano 的回答那样访问您的应用程序窗口。为什么要重新发明轮子?每个AVPlayerViewController 都有一个contentOverlayView 属性,允许您在播放器和控件之间放置视图。

    首先,创建一个新的AVPlayerItem 并监听该项目的AVPlayerItemDidPlayToEndTimeNotification 通知。将项目加载到播放器中并开始播放。

    一旦项目完成,您指定用于侦听AVPlayerItemDidPlayToEndTimeNotification 通知的选择器将被调用。在该选择器中,直接访问contentOverlayView 并添加您的按钮:

    在某些视图控制器或其他对象中:

    let playerVC = AVPlayerViewController()
    
    // ...
    
    func setupPlayer {
    
        let playerItem = AVPlayerItem(...)
        playerVC.player?.replaceCurrentItemWithPlayerItem(playerItem)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(VC.itemFinished), name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
        self.presentViewController(playerVC, animated: true) { 
            self.playerVC.player?.play()
        }
    }
    
    func itemFinished() {
        let btn = UIButton(type: .System)
        btn.addTarget(self, action: #selector(VC.buttonTapped), forControlEvents: .TouchUpInside)
        self.playerVC.contentOverlayView?.addSubview(btn)
    }
    
    func buttonTapped() {
        print("button was tapped")
        // replay/comment logic here
    }
    

    如 cmets(和 rejected edit)中所述,按钮在 contentOverlayView 中可能不起作用。如需其他解决方案,请参阅Pyro's answer

    你也可以继承 AVPlayerViewController 并在你的子类的实例中做所有事情,但是 Apple warns against that

    不要继承AVPlayerViewController。不支持覆盖此类的方法,并会导致未定义的行为。

    【讨论】:

    • 这真的有效吗?我可以在内容视图中添加视图或按钮,但由于某种原因,我似乎没有让按钮接收触摸...我已经尝试使用 iOS 10 和 11。
    • 我不使用 avplayerviewcontroller。如何仅使用 player 或 playerLayer 达到相同的效果?
    【解决方案3】:

    根据您的问题和 Ramis 的评论/代码,我制作了一个示例代码,您可以尝试

    正如 JAL 所述,contentOverlayView 应该是在AVPlayerController 中显示对视频的控制的最佳选择,但根据我的示例演示,contentOverlayView 没有按钮或其他控件的任何用户交互,就像您在 AVPlayerController 的 3D 视图中检查它在 contentOverlayView 前面有 AVTouchIgnoringView/UIView,这可能是用户与 contentOverlayView 交互的问题.

    所以另一种解决方案是在 AVPlayerViewController 中添加叠加视图

    func addContentOverlayView() {
    
        OverlayView.frame = CGRectMake(0,30,AVPlayerVC.view.bounds.width, 100)
        OverlayView.hidden = true
        OverlayView.backgroundColor = UIColor ( red: 0.5, green: 0.5, blue: 0.5, alpha: 0.379 )
    
        let btnNext = UIButton(frame:CGRectMake(AVPlayerVC.view.bounds.width - 60,0,60,44))
        btnNext.setTitle(">>", forState:.Normal)
        btnNext.addTarget(self, action:"playNext", forControlEvents:.TouchUpInside)
        //        btnNext.layer.borderColor = UIColor ( red: 0.0, green: 0.0, blue: 1.0, alpha: 0.670476140202703 ).CGColor
        //        btnNext.layer.borderWidth = 1.0
        OverlayView.addSubview(btnNext)
    
        let btnReplay = UIButton(frame:CGRectMake((AVPlayerVC.view.bounds.width/2)-40,0,80,44))
        btnReplay.setTitle("Replay", forState:.Normal)
        btnReplay.addTarget(self, action:"replayVideo", forControlEvents:.TouchUpInside)
        OverlayView.addSubview(btnReplay)
    
        let btnPrevious = UIButton(frame:CGRectMake(0,0,80,44))
        btnPrevious.setTitle("<<", forState:.Normal)
        btnPrevious.addTarget(self, action:"previousVideo", forControlEvents:.TouchUpInside)
        OverlayView.addSubview(btnPrevious)
    
        let btnComment = UIButton(frame:CGRectMake((AVPlayerVC.view.bounds.width/2)-70,40,140,44))
        btnComment.setTitle("Comments", forState:.Normal)
        btnComment.addTarget(self, action:"openComments", forControlEvents:.TouchUpInside)
        OverlayView.addSubview(btnComment)
    
        AVPlayerVC.view.addSubview(OverlayView);
    
    }
    
    func playNext() {
        prevItem = AVPlayerVC.player?.currentItem
        OverlayView.hidden = true
        commmentQueuePlayer.advanceToNextItem()
    }
    
    func replayVideo() {
        OverlayView.hidden = true
        AVPlayerVC.player?.currentItem?.seekToTime(kCMTimeZero)
        AVPlayerVC.player?.play()
    }
    
    func previousVideo() {
        OverlayView.hidden = true
        if prevItem != AVPlayerVC.player?.currentItem {
            if (commmentQueuePlayer.canInsertItem(prevItem!, afterItem:AVPlayerVC.player?.currentItem)) {
                //commmentQueuePlayer.insertItem(prevItem!, afterItem:AVPlayerVC.player?.currentItem)
                commmentQueuePlayer.replaceCurrentItemWithPlayerItem(prevItem)
                prevItem = AVPlayerVC.player?.currentItem
                replayVideo()
            }
        } else {
            replayVideo()
            //Else display alert no prev video found
        }
    }
    
    func stopedPlaying() {
        if prevItem == nil {
            prevItem = AVPlayerVC.player?.currentItem
        }
        OverlayView.hidden = false
    }
    

    在初始设置中,我们设置了 AVPlayerController、AVQueuePlayer 等...那时我们可以在 AVPlayerController 上添加叠加层

    对于上一个项目,没有直接可用的项目,根据文档,一旦播放下一个项目,该项目将被删除,所以我们有两个选项,如 replaceCurrentItemWithPlayerIteminsertItem(item: AVPlayerItem, afterItem: AVPlayerItem?)

    如果您需要检查完整的代码,您可以从以下位置进行检查: https://gist.github.com/Pyrolr/debb4fca8f608b1300e099a5b3547031

    注意:这就像原型一样,并非在所有情况下都能完美运行,但它可以帮助您了解您想要的基本功能,并且您可以根据您的要求进行改进/优化

    【讨论】:

      【解决方案4】:

      我建议查找 AVPlayerLayer 作为在视频顶部显示按钮和其他内容的一种方式。

      请参阅Advances in AVFoundation Playback WWDC 演示文稿。

      另外,查看AVFoundationSimplePlayer-iOS 示例项目。

      本质上,您创建一个视图来托管您的播放器,然后将视图后面的层变成 AVPlayerLayer。

      class PlayerView: UIView {
          var player: AVPlayer? {
              get {
                  return playerLayer.player
              }
      
              set {
                  playerLayer.player = newValue
              }
          }
      
          var playerLayer: AVPlayerLayer {
              return layer as! AVPlayerLayer
          }
      
          override class var layerClass: AnyClass {
              return AVPlayerLayer.self
          }
      }
      

      【讨论】:

      • 我发现这个答案很有用。
      • 如何使用这个类请帮帮我?
      【解决方案5】:

      检查下面的代码,我可以在叠加层上添加按钮以及正在调用按钮事件。

      var playerViewController: AVPlayerViewController?
      var OverlayView = UIView()    
          
      private lazy var button1: UIButton = {
                          let selfType = type(of: self)
                          let button = UIButton(frame: .init(origin: .zero, size: .init(width: selfType.musicWidth, height: selfType.musicHeight)))
                          button.setImage(UIImage(named: "star"), for: .normal)
                          button.addTarget(self, action: #selector(button1DidSelect), for: .touchUpInside)
                          button.translatesAutoresizingMaskIntoConstraints = false
                          NSLayoutConstraint.activate([
                              button.widthAnchor.constraint(equalToConstant: selfType.musicWidth),
                              button.heightAnchor.constraint(equalToConstant: selfType.musicHeight)
                          ])
                          return button
                      }()
              
      override func viewDidAppear(_ animated: Bool) {
                          super.viewDidAppear(true)
                          guard let url = URL(string: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4") else { return  }
                          let player = AVPlayer(url: url)
                          self.playerViewController = AVPlayerViewController()
                          guard let playerViewController = self.playerViewController else { return }
                          playerViewController.player = player
                          
                          present(playerViewController, animated: true) {
                              playerViewController.player?.play()
                          }
                      
                              self.addButtonsOnOverlayView()
                              self.playerViewController?.showsPlaybackControls = false
                              self.isHideOverlayControls = false
                      }
          
           
          
      @objc private func button1DidSelect() {
                      print("button1 Selected")
                      
                  }
          
       private func addButtonsOnOverlayView() {
                  
                  guard let overlayView = self.playerViewController?.contentOverlayView else { return }
                  
                  if !self. button1.isDescendant(of: overlayView) {
                      overlayView.addSubview(self.musicFirstButton)
                       self.playerViewController?.showsPlaybackControls = true
          
                  }
                  
                     NSLayoutConstraint.activate([
                      button1.leadingAnchor.constraint(equalTo: overlayView.leadingAnchor, constant: 20),
                      button1.topAnchor.constraint(equalTo: overlayView.topAnchor, constant: 20),
                  ])
                
              }
      

      【讨论】:

        猜你喜欢
        • 2014-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-07
        • 1970-01-01
        相关资源
        最近更新 更多