iOS App启动图--视频

这篇文章要介绍的是,在软件启动的时候,呈现一个视频播放功能,目前主流的社交App启动时都有这样的功能,效果还蛮不错的。

目标

这里要实现的功能是,第一次进入软件,启动时播放一段较长的视频,并且有进入应用按钮,不点击按钮会一直循环播放视频,直到点击按钮才会跳转到应用内部;如果是第二次进入软件,则启动时播放一段较短的视频,播放完成直接进入到应用内部,且没有进入应用按钮

细节实现
1.怎样在启动时进入视频播放,在需要结束播放时退出视频播放

软件启动过程中,会最先显示LaunchScreen.storyboard,然后都会走AppDelegate中的方法:- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions。所以

  • 可以创建一个用于视频播放的控制器(下面说成AV控制器),在这个代理方法中将AV控制器,设置为根控制器,这样就可以进入视频播放了
  • 在需要结束播放的地方(点击事件或者播放完成),将需要显示的控制器设置为窗口的根控制器,这样就可以退出了
2.流畅性能处理---视频播放中断和刚开始播放时插入图片
  • 从LaunchScreen.storyboard到视频播放,会有一个间断,在这个地方添加一张图片,图片内容就和LaunchScreen.storyboard中的一样,然后LaunchScreen.storyboard中的图片和视频的第一帧一样,这样的话画面看起来就比较流畅了
  • 开始播放后,会有一个自带的通知--AVPlayerItemTimeJumpedNotification,添加观察者,在观察者的事件中,移除开始播放前插入的图片
  • 点击进入应用按钮,视频播放中断,跳转到应用界面中间会有个停顿,在这里添加一个图片,图片就是当前界面的截图,只需要很短的时间即可,这样看起来就比较流畅了
3.第一次进入和非第一次进入软件的处理
  • 第一次进入,会有进入应用按钮,并且,不点击则循环播放视频;而非第一次进入,则直接播放另一个较短的视频,播放完成,则跳转到应用。根据这个区别,添加一个布尔值的属性,通过[NSUserDefaults standardUserDefaults]来记录是否为第一次进入应用,然后进行相关处理。
  • 视频播放完成自带有这个通知--AVPlayerItemDidPlayToEndTimeNotification,添加观察者,第一次进入软件时,视频播放完成,在观察者的事件中,再次播放视频;第二次进入软件时,视频播放完成,在观察者的事件中,直接进入应用。

上代码
创建视频控制器AVPlayerVC,继承自AVPlayerViewController,可能刚创建会报错,需要引入AVKit框架---#import <AVKit/AVKit.h>,就不会报错了

#import <AVKit/AVKit.h>

@interface AVPlayerVC : AVPlayerViewController

@end

在AppDelegate中引入AVPlayerVC控制器,并设置根控制器

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[AVPlayerVC alloc] init];
    [self.window makeKeyAndVisible];
    // Override point for customization after application launch.
    return YES;
}

在视频播放器中添加属性

@interface AVPlayerVC ()
//播放开始之前的图片
@property(nonatomic,strong)UIImageView * startPlayerImageView;
//播放中断时的图片
@property(nonatomic,strong)UIImageView * pausePlayerImageView;
//进入应用按钮
@property(nonatomic,strong)UIButton * enterMainButton;
//是否第一次进入App
@property(nonatomic,assign)BOOL isFirstLunchApp;
@end

用到的宏和头文件

#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"
#import "AppDelegate.h"
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kIsFirstLunchApp @"isFirstLunchApp"

因为用到通知,和播放器,所以先在dealloc方法中将其注销

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (self.player) {
        self.player = nil;
    }
}

初始化视图、添加通知、初始化播放器

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initView];
}
#pragma mark -- 初始化视图
-(void)initView{
    //添加一个图片,在视频播放之前放一张图片,这张图片和LunchScreen.storyboard中的相同,这样的话效果看起来连贯
    self.startPlayerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"lauch"]];
    self.startPlayerImageView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    [self.contentOverlayView addSubview:self.startPlayerImageView];
    /*对于contentOverlayView 官方解释是这样的:A view displayed between the video content and the playback controls.*/
    //第一次进入软件播放长一点的视频,并且带有“进入应用的按钮”;第二次进入软件播放短一点的视频,并且无进入按钮
    self.isFirstLunchApp = [[NSUserDefaults standardUserDefaults] boolForKey:kIsFirstLunchApp];
    if (!self.isFirstLunchApp) {//第一次启动软件
        //添加“进入应用”按钮
        [self addEnterButton];
    }
    //添加监听通知
    [self addNotification];
    //初始化视频
    [self prepareAV];
}
-(void)addEnterButton{
    self.enterMainButton = [UIButton buttonWithType:UIButtonTypeCustom];
    _enterMainButton.frame = CGRectMake(24, kScreenHeight - 32 - 48, kScreenWidth - 48, 48);
    _enterMainButton.layer.borderWidth =1;
    _enterMainButton.layer.cornerRadius = 24;
    _enterMainButton.layer.borderColor = [UIColor whiteColor].CGColor;
    [_enterMainButton setTitle:@"进入应用" forState:UIControlStateNormal];
    [self.view addSubview:_enterMainButton];
    [_enterMainButton addTarget:self action:@selector(enterMainAction:) forControlEvents:UIControlEventTouchUpInside];
    _enterMainButton.hidden = YES;//先设置为隐藏,等过三秒的时间在显示该按钮,
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        _enterMainButton.hidden = NO;
    });
}
//添加通知
-(void)addNotification{
    //添加播放器的几个通知--1.播放开始的时候,要删掉开始的占位图,如果是第一次进入应用,在没有点击“进入应用”时,需要循环播放
    if (self.isFirstLunchApp) {
        //第二次进入app视频需要直接结束
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlaybackComplete) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];//视频播放结束时添加通知
    }else {
        //第一次进入app视频需要轮播
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlaybackAgain) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];//视频播放结束时添加通知
    }
    //播放开始
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlaybackStart) name:AVPlayerItemTimeJumpedNotification object:nil];
}
//初始化播放器
-(void)prepareAV{
    //首次运行
    NSString *filePath = nil;
    if (!self.isFirstLunchApp) {//没有值,说明是第一次
        //第一次安装
        filePath = [[NSBundle mainBundle] pathForResource:@"opening_long_1080*1920.mp4" ofType:nil];
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kIsFirstLunchApp];
    }else {
        filePath = [[NSBundle mainBundle] pathForResource:@"opening_short_1080*1920.mp4" ofType:nil];
    }
    //初始化player
    self.player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
    self.showsPlaybackControls = NO;
    //播放视频
    [self.player play];
}

点击事件和通知事件

#pragma mark -- 点击事件及通知事件
//进入按钮点击事件
-(void)enterMainAction:(UIButton*)sender{
    //暂停播放
    [self.player pause];
    //添加一个imageView,用于放置暂停播放时的图片
    self.pausePlayerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
    [self.contentOverlayView addSubview:self.pausePlayerImageView];
    self.pausePlayerImageView.contentMode = UIViewContentModeScaleAspectFit;//设置
    //截图并展示截图
    [self getoverPlayerImage];
    //播放结束要移除相关的对象
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self moviePlaybackComplete];
    });
    
}
//结束播放删除对应的对象和注销通知事件
-(void)moviePlaybackComplete{
    //移除播放前的占位图
    [self.startPlayerImageView removeFromSuperview];
    self.startPlayerImageView = nil;
    //移除暂停播放的占位图
    [self.pausePlayerImageView removeFromSuperview];
    self.pausePlayerImageView = nil;
    //跳转到新界面
    [self pushToNewController];
}
//循环播放事件
-(void)moviePlaybackAgain{
    //添加播放前的占位图
    self.startPlayerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"lauchAgain"]];
    _startPlayerImageView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    [self.contentOverlayView addSubview:_startPlayerImageView];
    [self.pausePlayerImageView removeFromSuperview];
    self.pausePlayerImageView = nil;
    //初始化player
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"opening_long_1080*1920.mp4" ofType:nil];
    self.player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
    self.showsPlaybackControls = NO;
    //播放视频
    [self.player play];
}
//开始播放通知事件
- (void)moviePlaybackStart {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.startPlayerImageView removeFromSuperview];
        self.startPlayerImageView = nil;
    });
}

私有方法

#pragma mark -- 私有方法
//获取截图
- (void)getoverPlayerImage {
    AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:self.player.currentItem.asset];
    gen.appliesPreferredTrackTransform = YES;
    NSError *error = nil;
    CMTime actualTime;
    CMTime now = self.player.currentTime;
    [gen setRequestedTimeToleranceAfter:kCMTimeZero];
    [gen setRequestedTimeToleranceBefore:kCMTimeZero];
    CGImageRef image = [gen copyCGImageAtTime:now actualTime:&actualTime error:&error];
    if (!error) {
        UIImage *thumb = [[UIImage alloc] initWithCGImage:image];
        self.pausePlayerImageView.image = thumb;
    }
    NSLog(@"%f , %f",CMTimeGetSeconds(now),CMTimeGetSeconds(actualTime));
    NSLog(@"%@",error);
}
//跳转到新的控制器
-(void)pushToNewController{
    AppDelegate * appde = (AppDelegate*)[UIApplication sharedApplication].delegate;
    UIViewController * mainC = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
    appde.window.rootViewController = mainC;
    [appde.window makeKeyWindow];
}

Demo下载
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容