开始篇,我们用AVFoundation中的AVPlayer配合AVPlayerLayer进行播放,但是我们不能控制其暂停/继续、进度条显示及进度拖动、已播时间/总时长显示,这些都没有,所以我们定制一个XIB来包装AVPlayer和AVPlayerLayer
完整代码见 https://github.com/targetcloud/VideoPlayer1
未封装使用没有进度、时间等
import UIKit
import AVFoundation
class ViewController: UIViewController {
lazy var player: AVPlayer = {
let url = URL(string: "http://v1.mukewang.com/57de8272-38a2-4cae-b734-ac55ab528aa8/L.mp4")
let player = AVPlayer(url: url!)
return player
}()
var layer: AVPlayerLayer?
override func viewDidLoad() {
super.viewDidLoad()
layer = AVPlayerLayer(player: player)
view.layer.addSublayer(layer!)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
player.play()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
layer?.frame = view.layer.bounds
}
}
//
// videoPlayer1.swift
// videoPlayer1
//
// Created by targetcloud on 2016/11/29.
// Copyright © 2016年 targetcloud. All rights reserved.
//
import UIKit
import AVFoundation
class videoPlayer1: UIView {
var playerItem : AVPlayerItem? {
didSet{
player?.replaceCurrentItem(with: playerItem)
player?.play()
}
}
var player : AVPlayer?
var playerLayer : AVPlayerLayer?
var isShowToolView : Bool?
var progressTimer : Timer?
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var toolView: UIView!
@IBOutlet weak var timeLabel: UILabel!
@IBOutlet weak var progressSlider: UISlider!
@IBOutlet weak var playOrPauseBtn: UIButton!
class func playerView()->videoPlayer1{
return Bundle.main.loadNibNamed("videoPlayer1", owner: nil, options: nil)?.first as! videoPlayer1
}
override func awakeFromNib() {
player = AVPlayer()
playerLayer = AVPlayerLayer(player: player)
imageView.layer.addSublayer(playerLayer!)
toolView.alpha = 0
isShowToolView = false
progressSlider.setThumbImage(UIImage(named:"thumbImage"), for: .normal)
progressSlider.setMaximumTrackImage(UIImage(named:"MaximumTrackImage"), for: .normal)
progressSlider.setMinimumTrackImage(UIImage(named:"MinimumTrackImage"), for: .normal)
removeProgressTimer()
addProgressTimer()
playOrPauseBtn.isSelected = true
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer?.frame = bounds
}
func removeProgressTimer(){
progressTimer?.invalidate()
progressTimer = nil
}
func addProgressTimer(){
progressTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(videoPlayer1.updateProgressInfo), userInfo: nil, repeats: true)
RunLoop.main.add(progressTimer!, forMode: RunLoopMode.commonModes)
}
func updateProgressInfo(){
timeLabel.text = stringWithCurrentTime(CMTimeGetSeconds((player?.currentTime())!),CMTimeGetSeconds((player?.currentItem?.duration)!))
progressSlider.value = Float(CMTimeGetSeconds((player?.currentTime())!) / CMTimeGetSeconds((player?.currentItem?.duration)!))
}
func stringWithCurrentTime(_ currentTime:TimeInterval,_ duration:TimeInterval)->String{
let dMin = Int(duration) / 60
let dSec = Int(duration) % 60
let durationString = String(format:"%02ld:%02ld",dMin,dSec)
let cMin = Int(currentTime) / 60
let cSec = Int(currentTime) % 60
let currentString = String(format:"%02ld:%02ld",cMin,cSec)
return currentString + "/" + durationString
}
@IBAction func playOrPause(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected{
player?.play()
addProgressTimer()
}else{
player?.pause()
removeProgressTimer()
}
}
@IBAction func switchOrientation(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
}
@IBAction func startSlider(_ sender: UISlider) {
removeProgressTimer()
}
@IBAction func slider(_ sender: UISlider) {
addProgressTimer()
let currentTime = TimeInterval(Float(CMTimeGetSeconds((player?.currentItem?.duration)!)) * progressSlider.value);
player?.seek(to: CMTimeMakeWithSeconds(currentTime, Int32(NSEC_PER_SEC)), toleranceBefore:kCMTimeZero, toleranceAfter:kCMTimeZero)
}
@IBAction func sliderValueChanged(_ sender: UISlider) {
let currentTime = TimeInterval(Float(CMTimeGetSeconds((player?.currentItem?.duration)!)) * progressSlider.value);
let duration : TimeInterval = CMTimeGetSeconds((player?.currentItem?.duration)!);
timeLabel.text = stringWithCurrentTime(currentTime ,duration)
}
@IBAction func tapAction(_ sender: UITapGestureRecognizer) {
UIView.animate(withDuration: 0.5, animations: { () -> Void in
if self.isShowToolView!{
self.toolView.alpha = 0
self.isShowToolView = false
}else{
self.toolView.alpha = 1
self.isShowToolView = true
}
})
}
}
使用如下:
//
// ViewController.swift
// videoPlayer1
//
// Created by targetcloud on 2016/11/29.
// Copyright © 2016年 targetcloud. All rights reserved.
//
import UIKit
import AVFoundation
class ViewController: UIViewController {
var playerView:videoPlayer1?
override func viewDidLoad() {
super.viewDidLoad()
playerView = videoPlayer1.playerView()
self.view.addSubview(playerView!)
let url = URL(string:"http://v1.mukewang.com/57de8272-38a2-4cae-b734-ac55ab528aa8/L.mp4")//
let item = AVPlayerItem(url : url!)
playerView?.playerItem = item
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerView?.frame = view.bounds
}
}
没有封装与封装后的效果对比(图1之前,图2图3之后)