在 AVPlayer 顶部绘制按钮
Draw button on top of AVPlayer
我必须在视频上方绘制标签或按钮 relay next previous , leave comment
。视频列表有它,一旦用户 select 来自 table 的一项,它需要播放,播放器播放完成后,那些按钮或标签应该出现在视频
之上
这是我的代码:
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)
}
这样的要求
我认为制作 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)
...
}
您正在使用 AVPlayerViewController
,因此没有理由像 Alessandro Ornano 的回答那样访问您应用程序的 window。为什么要重新发明轮子?每个 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
}
如评论中所述(以及 rejected edit), buttons may not work in the contentOverlayView
. For an alternate solution, see .
你也可以继承 AVPlayerViewController
并在你的子类的一个实例中做任何事情,但是 Apple warns against that:
Do not subclass AVPlayerViewController
. Overriding this class’s methods is unsupported and results in undefined behavior.
根据你的问题和 Ramis 的 comment/code,我制作了一个示例代码,你可以试试
如 JAL 所述,contentOverlayView
应该是在 AVPlayerController
中显示对视频的控制的最佳选择,但根据我的示例演示 contentOverlayView
没有与按钮或其他控件的任何用户交互,就好像您在 AVPlayerController
的 3D 视图中签入一样它有 AVTouchIgnoringView
/UIView
contentOverlayView
的前面,这可能是用户与 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 上添加覆盖
对于上一个项目,没有直接可用的,根据文档,一旦播放下一个项目,该项目将被删除,因此我们有两个选项,例如 replaceCurrentItemWithPlayerItem
或 insertItem(item: AVPlayerItem, afterItem: AVPlayerItem?)
如果您需要检查完整的代码,您可以从以下位置进行检查:
https://gist.github.com/Pyrolr/debb4fca8f608b1300e099a5b3547031
注意:这就像原型一样,并非在所有情况下都能完美运行,但它可以帮助您理解您想要的基本功能,并且您可以improve/optimise 根据您的要求
我建议查找 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
}
}
检查下面的代码,我可以在叠加层上添加按钮以及调用按钮事件。
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),
])
}
我必须在视频上方绘制标签或按钮 relay next previous , leave comment
。视频列表有它,一旦用户 select 来自 table 的一项,它需要播放,播放器播放完成后,那些按钮或标签应该出现在视频
这是我的代码:
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)
}
这样的要求
我认为制作 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)
...
}
您正在使用 AVPlayerViewController
,因此没有理由像 Alessandro Ornano 的回答那样访问您应用程序的 window。为什么要重新发明轮子?每个 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
}
如评论中所述(以及 rejected edit), buttons may not work in the contentOverlayView
. For an alternate solution, see
你也可以继承 AVPlayerViewController
并在你的子类的一个实例中做任何事情,但是 Apple warns against that:
Do not subclass
AVPlayerViewController
. Overriding this class’s methods is unsupported and results in undefined behavior.
根据你的问题和 Ramis 的 comment/code,我制作了一个示例代码,你可以试试
如 JAL 所述,contentOverlayView
应该是在 AVPlayerController
中显示对视频的控制的最佳选择,但根据我的示例演示 contentOverlayView
没有与按钮或其他控件的任何用户交互,就好像您在 AVPlayerController
的 3D 视图中签入一样它有 AVTouchIgnoringView
/UIView
contentOverlayView
的前面,这可能是用户与 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 上添加覆盖
对于上一个项目,没有直接可用的,根据文档,一旦播放下一个项目,该项目将被删除,因此我们有两个选项,例如 replaceCurrentItemWithPlayerItem
或 insertItem(item: AVPlayerItem, afterItem: AVPlayerItem?)
如果您需要检查完整的代码,您可以从以下位置进行检查: https://gist.github.com/Pyrolr/debb4fca8f608b1300e099a5b3547031
注意:这就像原型一样,并非在所有情况下都能完美运行,但它可以帮助您理解您想要的基本功能,并且您可以improve/optimise 根据您的要求
我建议查找 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
}
}
检查下面的代码,我可以在叠加层上添加按钮以及调用按钮事件。
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),
])
}