• ios实现启动页添加广告的功能
  • 老妖 发表于 2017/2/27 17:49:00 | 分类标签: ios开发 ios添加广告
  •  代码分析:

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

    思路分析: 

    启动页广告是在启动页消失后添加在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 = 100;
            adView.duration = 5;
            adView.waitTime = 3;
            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:100];
        
            // 模拟从服务器上获取广告图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 = 0,      //普通的倒计时+跳过
            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, 0);
            _timerWait = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
            dispatch_source_set_timer(_timerWait, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0);
        
            dispatch_source_set_event_handler(_timerWait, ^{
                if (_waitTime <= 0) {
                    _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 <= 0) {
                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, 0);
            _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
            dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0); // 每秒执行
        
            dispatch_source_set_event_handler(_timer, ^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (_duration <= 0) {
                        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 - 62, 32, 40, 40)];
                CAShapeLayer *layer = [CAShapeLayer layer];
                layer.fillColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4].CGColor;    // 填充颜色
                layer.strokeColor = [UIColor redColor].CGColor;                                 // 绘制颜色
                layer.lineCap = kCALineCapRound;
                layer.lineJoin = kCALineJoinRound;
                layer.lineWidth = 2;
                layer.frame = self.bounds;
                layer.path = [self getCirclePath].CGPath;
                layer.strokeStart = 0;
                [_timerView.layer addSublayer:layer];
                self.viewLayer = layer;
            
                UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(3, 3, 34, 34)];
                titleLabel.text = @"跳过";
                titleLabel.textColor = [UIColor whiteColor];
                [titleLabel setTextAlignment:NSTextAlignmentCenter];
                titleLabel.font = [UIFont systemFontOfSize:15];
                [_timerView addSubview:titleLabel];
                _remain = _duration * 20;
                _count = 0;
                UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(skipAction)];
                [_timerView addGestureRecognizer:tap];
            }
            return _timerView;
        }
    
        /* 绘制路径
         * path这个属性必须需要设置,不然是没有效果的/
         */
        - (UIBezierPath *)getCirclePath
        {
            return [UIBezierPath bezierPathWithArcCenter:CGPointMake(20, 20) radius:19 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, 0);
            _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
            dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 0.05 * NSEC_PER_SEC, 0); // 每秒执行
        
            dispatch_source_set_event_handler(_timer, ^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (_count >= _remain) {
                        dispatch_source_cancel(_timer);
                        self.viewLayer.strokeStart = 1;
                        [self dismiss];                         // 关闭界面
                    } else {
                        self.viewLayer.strokeStart += 0.01;
                        _count++;                               //剩余时间进行自加
                    }
                });
            });
            dispatch_resume(_timer);
        }

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


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

  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:老妖
  • 加入时间:2013/6/13 0:00:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮