簡介
iOS中簡單的視頻播放一般都是使用MPMoviePlayerViewController
類來實(shí)現(xiàn)显熏,但該類在iOS9已被棄用磁奖,官方推薦使用AVPlayerViewController
來代替〉ㄏ簦現(xiàn)在需要實(shí)現(xiàn)這樣一個(gè)效果竖共,第一次打開APP,播放一個(gè)短視頻撮弧,開始時(shí)準(zhǔn)備使用該類淀歇,后來發(fā)現(xiàn)完全沒必要使用一個(gè)ViewController
來實(shí)現(xiàn)這樣一個(gè)小功能易核。只要使用AVPlayer
、 AVPlayerLayer
兩個(gè)類即可實(shí)現(xiàn)房匆,AVPlayerViewController
內(nèi)部其實(shí)也是基于這兩個(gè)類實(shí)現(xiàn)的耸成。
具體實(shí)現(xiàn)
1. 實(shí)現(xiàn)視頻播放
AVPlayer
本身并不能顯示視頻,而且它也不像MPMoviePlayerController
有一個(gè)view屬性浴鸿。如果AVPlayer
要顯示必須創(chuàng)建一個(gè)播放器層AVPlayerLayer
用于展示井氢,播放器層繼承于CALayer
, 有了AVPlayerLayer
之后岳链,添加到控制器視圖的layer中即可花竞。
簡單實(shí)現(xiàn)代碼如下:
self.backgroundColor = [UIColor whiteColor];
AVPlayer *player = [[AVPlayer alloc] initWithURL:self.movieURL];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
[self.layer addSublayer:playerLayer];
playerLayer.videoGravity = AVLayerVideoGravityResize;
playerLayer.frame = [UIScreen mainScreen].bounds;
[self.player play];
2. 實(shí)現(xiàn)視頻循環(huán)播放
運(yùn)行即可發(fā)現(xiàn)啟動(dòng)視頻已經(jīng)完成了,代碼也不復(fù)雜掸哑,是不是太easy了约急?但是不知你發(fā)現(xiàn)沒有,幾十秒的視頻放完之后就停在視頻的最后一幀不動(dòng)了苗分,這樣不太友好厌蔽,如果能實(shí)現(xiàn)視頻循環(huán)播放就再好不過了。如果用MPMoviePlayerController
實(shí)現(xiàn)的話摔癣,可以設(shè)置repeatMode
,如果使用AVPlayer
奴饮,可以添加通知。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]
- (void)playbackFinished:(NSNotification *)notifation {
// 回到視頻的播放起點(diǎn)
[self.player seekToTime:kCMTimeZero];
[self.player play];
}
如此即可實(shí)現(xiàn)視頻的循環(huán)播放
3. 實(shí)現(xiàn)動(dòng)畫漸變
現(xiàn)在我們發(fā)現(xiàn)择浊,打開APP從啟動(dòng)圖到視頻播放的轉(zhuǎn)變太生硬了戴卜,添加個(gè)漸變動(dòng)畫效果更棒。
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:0.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.duration = 3.0f;
scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
scaleAnimation.delegate = self;
[playerLayer addAnimation:scaleAnimation forKey:nil];
這里我們給動(dòng)畫設(shè)置了代理琢岩,實(shí)現(xiàn)代理的如下方法:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
[self.player play];
}
目的就是在動(dòng)畫的時(shí)候不進(jìn)行視頻的播放投剥,在動(dòng)畫結(jié)束后再開始播放。這里有一點(diǎn)需要注意一下担孔,動(dòng)畫的delegate一定要在將動(dòng)畫設(shè)置到layer之前江锨,否在動(dòng)畫的代理方法不會執(zhí)行吃警。
4. 解決白屏問題
由于我們設(shè)置了控制器view的背景為白色,在啟動(dòng)圖到視頻開始播放的過程有個(gè)白屏的階段泳桦。不是很友好汤徽,如果能在動(dòng)畫開始時(shí)依然顯示啟動(dòng)圖效果會好很多。但在代碼中如果獲取啟動(dòng)圖片呢灸撰?話不多少,直接上代碼
+ (instancetype)getLaunchImage {
CGSize screenSize = [UIScreen mainScreen].bounds.size;
NSString *orientation = @"Portrait";
NSString *launchImageName = nil;
NSArray *imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
for (NSDictionary *dic in imagesDict) {
CGSize imageSize = CGSizeFromString(dic[@"UILaunchImageSize"]);
if (CGSizeEqualToSize(screenSize, imageSize) && [dic[@"UILaunchImageOrientation"] isEqualToString:orientation]) {
launchImageName = dic[@"UILaunchImageName"];
break;
}
}
return [UIImage imageNamed:launchImageName];
}
可以將該方法放在UIImage的分類中拼坎。具體的信息可以通過打印[[NSBundle mainBundle] infoDictionary]
查看浮毯,
現(xiàn)在可以獲取到啟動(dòng)圖了,然后我們將該圖片添加到控制器view中泰鸡,作為背景即可
CALayer *backLayer = [CALayer layer];
backLayer.frame = [UIScreen mainScreen].bounds;
backLayer.contents = (__bridge id _Nullable)([UIImage getLaunchImage].CGImage);
[self.layer addSublayer:backLayer];
由于只是作為顯示债蓝,沒必要使用UIImageView
,所以這里采用了更輕量級的Layer
來實(shí)現(xiàn)。
5. 內(nèi)存溢出問題
這里有一點(diǎn)需要 特別注意
CABasicAnimation的delegate是強(qiáng)應(yīng)用J⒘洹J渭!!不要罵爹余舶,不要罵娘啊鸭,在這點(diǎn)上被坑了太久。解決方法也很簡單匿值,自定義類實(shí)現(xiàn)CAAnimationDelegate
代理吧赠制。
全部完成,打完收工挟憔。具體代碼可參考github