前言

  由于项目中要用到启动页广告,所以做了简单的研究,同时借鉴网易新闻和蘑菇街的交互写了一个简单的demo,现在写出来供大家参考,可能由于个人局限会有一些bug和不完善的地方,也希望大家能够友善提醒和指正。

Github地址:https://github.com/Running2snail/LLFullScreenAd

效果图如下:

代码分析:
上面主要展示了广告图提过按钮显示的两种方式,一种是常见的计数倒计时+跳过的样式(大部分的广告启动页都是这种方式),一种是通过环形倒计时+跳过的样式(仿网易新闻)。下面我将分别介绍两种样式的简单原理。

思路分析:
启动页广告是在启动页消失后添加在window上显示,过程为获取广告图信息,然后下载广告图,其次显示并相应相应的点击跳转等事件。过程并不复杂,主要的问题在于启动时期比较短暂而且图片信息的获取和下载时间的不确定等问题。在这里主要通过设置一个等待计时器来在避免长时间的等待,同时利用SDWebImage来缓存图片数据用于下次的显示。另外圆形进度条的实现也比较简单,这里就不做过多的介绍,下面具体看主要的代码实现。

代码分析:

在AppDelegate.m文件中创建并添加到window上,同时下载广告图

AppDelegate.m

 @implementation AppDelegate

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[ViewController alloc] init];
[self.window makeKeyAndVisible]; [self addADView]; // 添加广告图
[self getADImageURL];
return YES;
} /** 添加广告图 */
- (void)addADView
{
LLFullScreenAdView *adView = [[LLFullScreenAdView alloc] init];
adView.tag = ;
adView.duration = ;
adView.waitTime = ;
adView.skipType = SkipButtonTypeCircleAnimationTest;
adView.adImageTapBlock = ^(NSString *content) {
NSLog(@"%@", content);
};
[self.window addSubview:adView];
} /** 获取广告图URL */
- (void)getADImageURL
{
// 此处推荐使用tag来获取adView,勿使用全局变量。因为在AppDelegate中将其设为全局变量时,不会被释放
LLFullScreenAdView *adView = (LLFullScreenAdView *)[self.window viewWithTag:]; // 模拟从服务器上获取广告图URL
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSString *urlString = @"http://s8.mogucdn.com/p2/170223/28n_4eb3la6b6b0h78c23d2kf65dj1a92_750x1334.jpg"; [adView reloadAdImageWithUrl:urlString]; // 加载广告图(如果没有设置广告图设置为空)
});
}

LLFullScreenAdView.h

#import <UIKit/UIKit.h>

    typedef NS_ENUM(NSUInteger, SkipButtonType) {
SkipButtonTypeNormalTimeAndText = , //普通的倒计时+跳过
SkipButtonTypeCircleAnimationTest, //圆形动画+跳过
SkipButtonTypeNormalText, //只有普通的跳过
SkipButtonTypeNormalTime, //只有普通的倒计时
SkipButtonTypeNone //无
}; typedef void(^adImageBlock)(NSString *content); //可以根据需要添加一些相应的参数 @interface LLFullScreenAdView : UIImageView /** 广告图的显示时间(默认5秒)*/
@property (nonatomic, assign) NSUInteger duration; /** 获取数据前,启动图的等待时间(若不设置则不启动等待机制)*/
@property (nonatomic, assign) NSUInteger waitTime; /** 右上角按钮的样式(默认倒计时+跳过)*/
@property (nonatomic, assign) SkipButtonType skipType; /** 广告图点击事件回调*/
@property (nonatomic, copy) adImageBlock adImageTapBlock; /** 加载广告图*/
- (void)reloadAdImageWithUrl:(NSString *)urlStr; @end

LLFullScreenAdView.m

  /** 获取启动图片 */
- (UIImage *)getLaunchImage
{
CGSize viewSize = [UIScreen mainScreen].bounds.size;
NSString *viewOrientation = @"Portrait"; // 横屏请设置成 @"Landscape"
UIImage *lauchImage = nil;
NSArray *imagesDictionary = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
for (NSDictionary *dict in imagesDictionary)
{
CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]);
if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]])
{
lauchImage = [UIImage imageNamed:dict[@"UILaunchImageName"]];
}
}
return lauchImage;
} /** 广告图加载前等待计时器 */
- (void)scheduledWaitTimer
{
if (_timerWait) dispatch_source_cancel(_timerWait); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
_timerWait = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, , , queue);
dispatch_source_set_timer(_timerWait, dispatch_walltime(NULL, ), 1.0 * NSEC_PER_SEC, ); dispatch_source_set_event_handler(_timerWait, ^{
if (_waitTime <= ) {
_flag = YES;
dispatch_source_cancel(_timerWait);
dispatch_async(dispatch_get_main_queue(), ^{
[self dismiss]; // 关闭界面
});
} else {
_waitTime--;
}
});
dispatch_resume(_timerWait);
} /** 获取广告图 */
- (void)reloadAdImageWithUrl:(NSString *)urlStr
{
if (urlStr.length <= ) {
if (_timerWait) dispatch_source_cancel(_timerWait);
[self removeFromSuperview];
return;
}
NSURL *imageUrl = [NSURL URLWithString:urlStr];
__weak typeof(self) weakSelf = self;
UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:urlStr];
if (cacheImage) { //查看是否有缓存
NSLog(@"cacheImage");
[weakSelf adImageShowWithImage:cacheImage];
} else {
NSLog(@"noCacheImage");
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:imageUrl options:SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize) { } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image && finished && error == nil) { [weakSelf adImageShowWithImage:image];
[[SDImageCache sharedImageCache] storeImage:image forKey:urlStr toDisk:YES];
}
}];
}
} /** 广告图显示倒计时 */
- (void)scheduledTimer
{
if (_timerWait) dispatch_source_cancel(_timerWait); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, , ,queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, ), 1.0 * NSEC_PER_SEC, ); // 每秒执行 dispatch_source_set_event_handler(_timer, ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (_duration <= ) {
dispatch_source_cancel(_timer);
[self dismiss]; // 关闭界面
} else {
[self showSkipBtnTitleTime:_duration];
_duration--;
}
});
});
dispatch_resume(_timer);
} /** 消失广告图 */
- (void)dismiss
{
NSLog(@"dismiss");
[UIView animateWithDuration:0.5 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.transform = CGAffineTransformMakeScale(1.2, 1.2);
self.alpha = 0.0;
} completion:^(BOOL finished) { [self removeFromSuperview];
}];
}

圆形进度条的简单实现

使用了CAShapeLayer的strokeStart和strokeEnd属性,实现起来十分的简单方便,通过设置Path的中心点、起始和终止的位置,并利用strokeStart和strokeEnd这两个属性支持动画的特点,我们通过以下代码就可以实现圆形进度条的效果

//懒加载一个计时器视图,并设置动画绘制的路径
- (UIView *)timerView
{
if (!_timerView) {
self.timerView = [[UIView alloc] initWithFrame:CGRectMake(MainScreenWidth - , , , )];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.fillColor = [UIColor colorWithRed: green: blue: alpha:0.4].CGColor; // 填充颜色
layer.strokeColor = [UIColor redColor].CGColor; // 绘制颜色
layer.lineCap = kCALineCapRound;
layer.lineJoin = kCALineJoinRound;
layer.lineWidth = ;
layer.frame = self.bounds;
layer.path = [self getCirclePath].CGPath;
layer.strokeStart = ;
[_timerView.layer addSublayer:layer];
self.viewLayer = layer; UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(, , , )];
titleLabel.text = @"跳过";
titleLabel.textColor = [UIColor whiteColor];
[titleLabel setTextAlignment:NSTextAlignmentCenter];
titleLabel.font = [UIFont systemFontOfSize:];
[_timerView addSubview:titleLabel];
_remain = _duration * ;
_count = ;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(skipAction)];
[_timerView addGestureRecognizer:tap];
}
return _timerView;
} /* 绘制路径
* path这个属性必须需要设置,不然是没有效果的/
*/
- (UIBezierPath *)getCirclePath
{
return [UIBezierPath bezierPathWithArcCenter:CGPointMake(, ) radius: startAngle:-0.5*M_PI endAngle:1.5*M_PI clockwise:YES];
} /** 广告图显示倒计时 */
- (void)setCircleTimer
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, , ,queue);
dispatch_source_set_timer(_timer, dispatch_walltime(NULL, ), 0.05 * NSEC_PER_SEC, ); // 每秒执行 dispatch_source_set_event_handler(_timer, ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (_count >= _remain) {
dispatch_source_cancel(_timer);
self.viewLayer.strokeStart = ;
[self dismiss]; // 关闭界面
} else {
self.viewLayer.strokeStart += 0.01;
_count++; //剩余时间进行自加
}
});
});
dispatch_resume(_timer);
}

如果想对CAShapeLayer做更多了解可参考这篇文章上手CAShapeLayer,动画其实并不难

常用的计时器有两种一种是NSTimer,另一种是GCD,但NSTimer受runloop的影响,由于runloop需要处理很多任务,导致NSTimer的精度降低,在日常开发中,如果我们需要对定时器的精度要求很高的话,可以考虑dispatch_source_t去实现 。dispatch_source_t精度很高,系统自动触发,是系统级别的源。而且使用 NSTimer 时,如果使用不当就容易出现内存泄露,所以计时器建议使用GCD来实现。

上面的实现比较简单,所以也没有用太多的解释,如果感兴趣可以看下源代码,如果有好的建议或者疑问可以留言探讨。另外如果喜欢或者感觉对你有帮助最好能给个Star,非常感谢。

Github地址:https://github.com/Running2snail/LLFullScreenAd

iOS 快速集成启动页广告的更多相关文章

  1. iOS开发 关于启动页和停留时间的设置

    引言: 在开发一款商业App时,我们大都会为我们的App设置一个启动页. 苹果官方对于iOS启动页的设计说明: 为了增强应用程序启动时的用户体验,您应该提供一个启动图像.启动图像与应用程序的首屏幕看起 ...

  2. iOS仿写有妖气漫画、视频捕获框架、启动页广告页demo、多种动画效果等源码

    iOS精选源码 以tableview的section为整体添加阴影效果/ta'b'le'vi'e'w顶部悬浮.... 一个可以轻松应用自定义过滤器的视频捕获框架. 基于UITableView的组件,旨 ...

  3. iOS快速集成友盟社会化分享功能(v6.1.1)

    1.  U-Share SDK集成 1.1 下载U-Share SDK 通过iOS社会化组件选择所需的社交平台后进行下载,下载链接http://dev.umeng.com/social/ios/sdk ...

  4. iOS 快速集成ijkplayer视频直播与录播框架

    最近由于需求的变动,项目内把最初最简单的原生直播框架变成了B站开源的ijkplayer框架,下面把具体的过程总结一下整个过程都比较简单,重要的是理解的过程,集成完毕之后,视频的用户体验比苹果原生好了很 ...

  5. IOS快速集成下拉上拉刷新

    http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5% ...

  6. 混合开发之iOS快速集成DSBridge

    DSBridge-IOS github:https://github.com/wendux/DSBridge-IOS 使用 Native 实现API 代理类 //JsApiTest.m @implem ...

  7. iOS快速集成检查更新

    一直以为Appstore有了检查版本是否更新的机制,我们在APP上做这个更新功能会被拒,但是也有看到一些APP也是做了这个更新功能的.因为在网上没有找到完全正确的方法能获取到iTunes里的数据的,于 ...

  8. iOS 启动页后广告Demo

    重点! 对于启动页后的广告,相信大家也都看到过很多很多的,比如我自己常看到的有 QQ音乐,爱奇艺了.你点击了APP,它会启动就会随之启动..其实这些APP的启动页是没有消失的,你去认真的观察一下!所以 ...

  9. iOS swift 启动页加载广告(图片广告+视频广告)

    一般app在启动的时候都会有广告页,广告页用来加载自己的或者第三方的广告,广告的展示形式也多种多样,最近在看swift相关的东西,这里将提供支持加载图片广告和视频广告的解决方案 思路: 我们知道在加载 ...

随机推荐

  1. 【转】安卓必备Java基础

    [转]http://www.zhihu.com/question/19937886(里面提到的知识点的链接) 1. Java 语言基础 谈到Java 语言基础学习的书籍,大家肯定会推荐Bruce Ec ...

  2. 用C#开发一个 UWP BLUETOOTH BLE 扫描APP

    什么是WINDOWS UWP UWP即Windows 10 中的Universal Windows Platform简称.即Windows通用应用平台,在Win 10 Mobile/Surface(W ...

  3. 环信 之 iOS 客户端集成四:集成UI 之 会话列表

    1. 初始化 EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] ...

  4. TortoiseSVN使用简介(收藏)

    TortoiseSVN使用简介 1.安装及下载client 端 2.什么是SVN(Subversion)? 3.为甚么要用SVN? 4.怎么样在Windows下面建立SVN Repository? 5 ...

  5. windows下修改apache并发数

    还没有尝试 修改apache的最大连接数,方法如下: 步骤一 先修改 /path/apache/conf/httpd.conf文件. # vi httpd.conf 将“#Include conf/e ...

  6. js原生设计模式——2面向对象编程之闭包1

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  7. bootstrap的alert提示框的关闭后再显示问题

    bootstrap中有alert组件,如果点击关闭按钮后该组件会被删除而不是被隐藏,想再显示怎么办呢? bootstrap-alert.js源码片段: function removeElement() ...

  8. thinkphp 3.2 模型的使用示例

    原来以为thinkPHP的 model 就和PHPCMS一样  就起到一个连接数据库的作用,今天看了视频,才发现这个也是 mvc中的m 使用方法可以使用 D() 方法 下面是 UserControll ...

  9. easyUI progressbar组件

    easyUI progressbar组件: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  10. CSS页面渲染优化属性will-change

    前面的话   当我们通过某些行为(点击.移动或滚动)触发页面进行大面积绘制的时候,浏览器往往是没有准备的,只能被动使用CPU去计算与重绘,由于没有事先准备,应付渲染够呛,于是掉帧卡顿.而CSS属性wi ...