前言

  由于项目中要用到启动页广告,所以做了简单的研究,同时借鉴网易新闻和蘑菇街的交互写了一个简单的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 class加载机制及对象生成机制

    java class加载机制及对象生成机制 当使用到某个类,但该类还未初始化,未加载到内存中时会经历类加载.链接.初始化三个步骤完成类的初始化.需要注意的是类的初始化和链接的顺序有可能是互换的. Cl ...

  2. JQuery基础知识(2)

    JQuery基础知识(2) JQuery滑动效果 1. JQuery slideDown(); 语法: $(selector).slideDown(speed,callback); 可选的 speed ...

  3. 温故知新 javascript 正则表达式

    很长时间没看 正则表达式了,碰巧今天用到,温故知新了一把 看书学习吧 50% 的举一反三练习中的原创.   一 javascript正则表达式的基本知识 1     javascript 正则对象创建 ...

  4. Yii 1.0 基础

    骨架搭建 1.下载2.windows 创建PHP环境变量,找到php.exe的目录D:\wamp\bin\php\php5.3.5,右键我的电脑,属性\高级设置,path最后添加 ;D:\wamp\b ...

  5. js模块化开发——前端模块化

    在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可:如今CPU.浏览器性能得到了极大的提升,很多页面逻辑迁移到了客 户端(表单验证等),随着web2.0时代的到来,Ajax技术 ...

  6. js框架Modernizr是什么东西? 他是前端开发HTML5和CSS3的强有力前端js检测类库

    最近在研究modernizr的前端框架,发现这个Modernir对前端写页面非常友好,并且能够很快的建立起适应任何设备的html页面哦.在这里分享下基础教程,让大伙对modernizr是什么?做什么用 ...

  7. Unity3D 相关技术

    slua相关shader编程相关animation相关attack check攻击检测相关

  8. TIMESTAMP和DATETIME哪个好

    日期范围 TIMESTAMP 支持从'1970-01-01 00:00:01′ 到 '2038-01-19 03:14:07′ UTC. 这个时间可能对目前正在工作的人来说没什么问题,可以坚持到我们退 ...

  9. 【Scala】Scala之Control Structures

    一.前言 前面学习了Scala的Numbers,接着学习Scala的Control Structures(控制结构). 二.Control Structures Scala中的控制结构与Java中的颇 ...

  10. HDU5878(打表)

    I Count Two Three Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...