启动页面添加自定义图片

2016-10-02  本文已影响0人  HaloMartin

做这个东西的话,其实主要是因为一件事,我会比较经常食用手机迅雷下载电影,每次开启迅雷,都会默认来一段广告,这种强制的让使用者看广告的行为虽然让人很讨厌,但是本着好奇就认真挖掘的原则,看了一下网上的介绍,再自己实践了一下。
1, AppDelegate,入口,处理不同的回调,比如现在定义的三种不同结果,一是广告时间耗尽,未点击广告,也未点击跳过广告按钮了;二是点击广告;三是点击跳过按钮,程序中只是简单的根据不同的事件定义了不同的回调,并未继续做进一步的处理

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    /*
     简书主页:http://www.jianshu.com/users/1bacae3170dd/latest_articles
     */
    /*添加广告
     1.初始化,选择屏占比
     2.设置广告总时长,可跳过,默认是6秒
     3.启动计时器
     */
//    MCLaunchAdView* view = [[MCLaunchAdView alloc] initWithWindow:self.window with:MCAdViewTypeFullScreen];
//    MCLaunchAdView* view = [[MCLaunchAdView alloc] initWithWindow:self.window with:MCAdViewTypeHalfScreen];
//    MCLaunchAdView* view = [[MCLaunchAdView alloc] initWithWindow:self.window with:MCAdViewTypeThreeQuarters];
    MCLaunchAdView* view = [[MCLaunchAdView alloc] initWithWindow:self.window with:MCAdViewTypeFiveSixths];
    //显示本地图片
//    view.localImageName = @"adImage_lion.png";
    //显示网络图片
    view.imageURL = @"http://imgsrc.baidu.com/forum/pic/item/65c1a9cc7b899e51371108904aa7d933c9950d56.jpg";
//    http://imgsrc.baidu.com/forum/pic/item/65c1a9cc7b899e51371108904aa7d933c9950d56.jpg
    [view setTimer:6];
    [view startTimer];
    view.clickBlock = ^(MCQuitLaunchAdStyle tag){
        MCQuitLaunchAdStyle style = MCQuitLaunchAdStyleDefault;
        switch (tag) {
            case MCQuitLaunchAdStyleTimeOut:{
                NSLog(@"%@",NSLocalizedString(@"时间耗尽", nil));
                style = MCQuitLaunchAdStyleTimeOut;
            }
                break;
            case MCQuitLaunchAdStyleSkip:{
                NSLog(@"%@",NSLocalizedString(@"跳过广告", nil));
                style = MCQuitLaunchAdStyleSkip;
            }
                break;
            case MCQuitLaunchAdStyleJumpToURL:{
                NSLog(@"%@",NSLocalizedString(@"进入广告", nil));
                style = MCQuitLaunchAdStyleJumpToURL;
            }
                break;
            default:{
                NSLog(@"%@",NSLocalizedString(@"未知原因", nil));
                style = MCQuitLaunchAdStyleDefault;
            }
                break;
        }
        ViewController* vc = [[ViewController alloc] initWithLaunchStyle:style];
        vc.view.backgroundColor = [UIColor whiteColor];
        self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc];
    };
    //打印mainbundle
    NSDictionary* dict = [[NSBundle mainBundle] infoDictionary];
    NSLog(@"%@",dict);
    //
    return YES;
}

2, MCLaunchAdView,主要UI,显示在App上的启动页,可以看到的东西,都是在这里面

MCLaunchAdView.h
#import <UIKit/UIKit.h>
/*广告显示屏幕占比类型,对应的NSUInteger竟然选择有意义一点的*/
typedef NS_ENUM(NSUInteger, MCAdViewType) {
    MCAdViewTypeFullScreen = 1,//全屏
    MCAdViewTypeHalfScreen = 2,//半屏
    MCAdViewTypeThreeQuarters = 4,//四分之三屏
    MCAdViewTypeFiveSixths = 6,//六分之五屏
};

/*广告结束的方式*/
typedef NS_ENUM(NSUInteger, MCQuitLaunchAdStyle) {
    MCQuitLaunchAdStyleDefault = 0,
    MCQuitLaunchAdStyleTimeOut,//时间耗尽
    MCQuitLaunchAdStyleSkip,//跳过广告
    MCQuitLaunchAdStyleJumpToURL,//进入广告
};

/*块回调,广告结束后根据不同的结束方式处理下一步*/
typedef void (^MCClick) (MCQuitLaunchAdStyle tag);

/*广告*/
#pragma mark - MCLaunchAdView
@interface MCLaunchAdView : UIView

@property (nonatomic, strong) UIWindow* window;
@property (nonatomic, strong) NSString* localImageName;//本地图片名
@property (nonatomic, strong) NSString* imageURL;//网络图片名
@property (nonatomic, copy) MCClick clickBlock;//块回调,处理不同的操作

-(instancetype)initWithWindow:(UIWindow*)window with:(MCAdViewType)type;
-(void)setTimer:(NSInteger)time;
-(void)startTimer;
@end
MCLaunchAdView.m
//
//  MCLaunchAdView.m
//  MCLaunchAd
//
//  Created by 朱进林 on 9/16/16.
//  Copyright © 2016 Martin Choo. All rights reserved.
//

#import "MCLaunchAdView.h"
#import "MCCountingButton.h"
#import "UIImageView+WebCache.h"

#define screenWidth [UIScreen mainScreen].bounds.size.width
#define screenHeight [UIScreen mainScreen].bounds.size.height

#define TIMER_INTERVAL 0.04 //25帧每秒
#define SKIPBUTTONSIZE 30

#pragma mark - MCLaunchAdView
@interface MCLaunchAdView()
{
    MCCountingButton* _countingBtn;//跳过广告按钮
}
@property (nonatomic) MCAdViewType adViewtype;
@property (nonatomic, strong) UIImageView* adView;/*广告界面*/
@property (nonatomic) NSInteger adTime;//广告时长,默认6秒
@property (nonatomic) CGFloat adTimeLeft;/*剩余时间,用于计算时间是否耗尽*/
@property (nonatomic, strong) NSTimer* countTimer;/*计时器*/
@end

@implementation MCLaunchAdView

/*初始化*/
-(instancetype)initWithWindow:(UIWindow*)window with:(MCAdViewType)type
{
    self = [super init];
    if (self) {
        //
        self.window = window;
        [window makeKeyAndVisible];
        self.adViewtype = type;
        self.adTime = 6;//默认6秒
        self.adTimeLeft = self.adTime;
        [self initailView];
        [self.window addSubview:self];
    }
    return self;
}

-(void)initailView
{
    //广告界面
    {
        UIImageView* imgView = [[UIImageView alloc] init];
        imgView.contentMode = UIViewContentModeScaleToFill;//因为图片不一定铺满整个屏幕,所以这里暂时做了拉伸
        [self addSubview:imgView];
        self.adView = imgView;
    }
    //跳过按钮
    {
        MCCountingButton* countingBtn = [[MCCountingButton alloc] initWithFrame:CGRectMake(0, 0, SKIPBUTTONSIZE, SKIPBUTTONSIZE)];
        [countingBtn addTarget:self action:@selector(skipButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
        [self.adView addSubview:countingBtn];
        _countingBtn = countingBtn;
    }
}

-(void)layoutSubviews
{
    self.frame = CGRectMake(0, 0, screenWidth, screenHeight);
    //设置启动界面的背景,显示logo
    NSString* imgName = [self getBestLaunchImage];
    UIImage* img = [UIImage imageNamed:imgName];
    self.layer.contents = (id)img.CGImage;
    //根据不同的广告占屏比设置不同的布局
    if (self.adViewtype == MCAdViewTypeFullScreen) {
        self.adView.bounds = CGRectMake(0, 0, screenWidth, screenHeight);
    }else if (self.adViewtype == MCAdViewTypeHalfScreen) {
        self.adView.bounds = CGRectMake(0, 0, screenWidth, 2*screenHeight/3);
    }else if (self.adViewtype == MCAdViewTypeThreeQuarters) {
        self.adView.bounds = CGRectMake(0, 0, screenWidth, 3*screenHeight/4);
    }else if (self.adViewtype == MCAdViewTypeFiveSixths) {
        self.adView.bounds = CGRectMake(0, 0, screenWidth, 5*screenHeight/6);
    }else {
        self.adView.bounds = CGRectMake(0, 0, screenWidth, screenHeight);
    }
    self.adView.center = CGPointMake(screenWidth/2, self.adView.bounds.size.height/2);
    //跳过按钮的布局
    _countingBtn.center = CGPointMake(screenWidth-SKIPBUTTONSIZE/2-5, SKIPBUTTONSIZE/2+20);
    _countingBtn.tickTockInterval = TIMER_INTERVAL*1000;//设置计时间隔
    _countingBtn.totalTime = self.adTime;//设置总时长
}
/*设置计时器时长,不调用这个方法,就使用计时器默认的6秒*/
-(void)setTimer:(NSInteger)time
{
    self.adTime = time;
    self.adTimeLeft = time;
}
/*启动计时器*/
-(void)startTimer
{
    //添加计时器
    self.countTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(TickTock) userInfo:nil repeats:YES];
}
/*关闭计时器*/
-(void)closeTimer
{
    //关闭
    if (self.countTimer) {
        [self.countTimer invalidate];
        self.countTimer = nil;
    }
}

#pragma mark - Action
/*过了一个计时单位TIMER_INTERVAL,检查剩余时间*/
-(void)TickTock
{
    if (self.adTimeLeft > 0) {
        //默认6秒,时间未耗尽,继续展示
        self.adTimeLeft = self.adTimeLeft - TIMER_INTERVAL;
        [_countingBtn counting];
    }else {
        //默认6秒,时间耗尽
        [self closeTimer];
        if (self.clickBlock) {
            self.clickBlock(MCQuitLaunchAdStyleTimeOut);
        }
    }
}
/*响应点击跳过按钮事件*/
-(void)skipButtonClicked:(UIButton*)btn
{
    [self closeTimer];
    if (self.clickBlock) {
        self.clickBlock(MCQuitLaunchAdStyleSkip);
    }
}
/*响应点击广告事件*/
-(void)jumpToURL:(UITapGestureRecognizer*)recognizer
{
    [self closeTimer];
    if (self.clickBlock) {
        self.clickBlock(MCQuitLaunchAdStyleJumpToURL);
    }
}

#pragma mark - 获取最佳启动图
/*获取最佳启动图,根据硬件设备分辨率,从info.plist中获取图片名,需要在plist中添加相关的图片信息,从而适配不同尺寸的设备*/
-(NSString*)getBestLaunchImage
{
    NSString* launchImage = nil;
    CGSize viewSize = [UIScreen mainScreen].bounds.size;
    NSString* viewOrientation = @"Portrait";//如需设置横屏,请修改为Landscape,对应的viewSize也要切换一下
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
        viewSize = CGSizeMake(viewSize.height, viewSize.width);
        viewOrientation = @"Landscape";
    }
    //比较设备分辨率和图片尺寸,取得匹配的图片名
    NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
    for (NSDictionary* dict in imagesDict) {
        CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]);
        if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]])
            //这边会有问题,因为屏幕占比不一定全屏,所以这边其实还要进一步截取屏幕的大小,但是这边我省略了,外部在调用的时候我做了拉伸的处理
            launchImage = dict[@"UILaunchImageName"];
    }
    //没有匹配的图片,取默认的图片名
    if (!launchImage) {
        launchImage = @"LaunchImageIconLogo_930.png";
    }
    return launchImage;
}

#pragma mark -
/*重写setter方法,支持GIF图的显示*/
-(void)setLocalImageName:(NSString *)localImageName
{
    _localImageName = localImageName;
    if (_localImageName) {
        if ([[_localImageName uppercaseString] rangeOfString:@".GIF"].location != NSNotFound) {
            _localImageName = [_localImageName stringByReplacingCharactersInRange:[[_localImageName uppercaseString] rangeOfString:@".GIF"] withString:@""];
            NSData* gifData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:_localImageName ofType:@"gif"]];
            UIWebView* webView = [[UIWebView alloc] initWithFrame:self.adView.frame];
            webView.backgroundColor = [UIColor clearColor];
            webView.scalesPageToFit = YES;
            [webView loadData:gifData MIMEType:@"image/gif" textEncodingName:@"" baseURL:[NSURL URLWithString:@""]];
            [self.adView addSubview:webView];
            [self.adView bringSubviewToFront:_countingBtn];
        }else {
            self.adView.image = [UIImage imageNamed:_localImageName];
        }
        //添加点击广告监听,在此处添加,避免没有图片时点击区域依然跳转的发生
        UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jumpToURL:)];
        self.adView.userInteractionEnabled = YES;
        [self.adView addGestureRecognizer:tap];
    }
}
-(void)setImageURL:(NSString *)imageURL
{
    _imageURL = imageURL;
    if (_imageURL) {
        SDWebImageManager* manager = [SDWebImageManager sharedManager];
        [manager downloadImageWithURL:[NSURL URLWithString:_imageURL] options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
            NSLog(@"receivedSize:%ld, expectedSize:%ld",receivedSize,expectedSize);
        } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
            if (image) {
                self.adView.image = image;
                //添加点击广告监听,在此处添加,避免没有图片时点击区域依然跳转的发生
                UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(jumpToURL:)];
                self.adView.userInteractionEnabled = YES;
                [self.adView addGestureRecognizer:tap];
            }
        }];
    }
}
@end

3, MCCountingButton,倒计时按钮,也就是跳过广告按钮,这边是依照设置的倒计时总时长画个圆环,可以扩展一下,加上一些其它的动画,比如广告图下面加进度条,显示读秒的跳过按钮,模仿水位上升的倒计时等,这些实现起来原来都是相似的,可以简单的设置一个定时器,固定时间间隔后更新界面,再灵活的使用一下UIBezierPath和CAShapeLayer,即可得到自己想要的

MCCountingButton.h
#import <UIKit/UIKit.h>

/** 带倒计时的跳过按钮
 *  初始化后需设置总时长和间隔时间
 */
@interface MCCountingButton : UIButton
@property (nonatomic) NSInteger totalTime;//总时长,单位秒
@property (nonatomic) NSInteger tickTockInterval;//计时间隔单位,表示两次计数间的时间间隔,单位毫秒

-(instancetype)initWithFrame:(CGRect)frame;
/**
 *  改变进度条末端位置,循环调用实现进度条刷新
 */
-(void)counting;
@end
MCCountingButton.m
//
//  MCCountingView.m
//  MCLaunchAd
//
//  Created by 朱进林 on 9/19/16.
//  Copyright © 2016 Martin Choo. All rights reserved.
//

#import "MCCountingButton.h"

#pragma mark - MCCountingButton
@interface MCCountingButton()
@property (nonatomic, strong) UIBezierPath* path;
@property (nonatomic, strong) CAShapeLayer* backgroundShapeLayer;
@property (nonatomic, strong) CAShapeLayer* shapeLayer;
@end

@implementation MCCountingButton

-(instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //
        self.totalTime = 6;//默认总时长6秒
        self.tickTockInterval = 40;//默认25下每秒
        [self initialView];
    }
    return self;
}

-(void)initialView
{
    //设置路径
    self.path = [UIBezierPath bezierPathWithOvalInRect:self.bounds];
    //灰色底层
    self.backgroundShapeLayer = [CAShapeLayer layer];
    self.backgroundShapeLayer.frame = self.bounds;
    self.backgroundShapeLayer.fillColor = [UIColor clearColor].CGColor;
    self.backgroundShapeLayer.lineWidth = 2.0f;
    self.backgroundShapeLayer.strokeColor = [UIColor lightGrayColor].CGColor;
    self.backgroundShapeLayer.strokeStart = 0.f;
    self.backgroundShapeLayer.strokeEnd = 1.f;
    self.backgroundShapeLayer.path = self.path.CGPath;
    [self.layer addSublayer:self.backgroundShapeLayer];
    //环形进度条,起始点=终结点=0,所以初始化时不可见
    self.shapeLayer = [CAShapeLayer layer];
    self.shapeLayer.frame = self.bounds;
    self.shapeLayer.fillColor = [UIColor clearColor].CGColor;
    self.shapeLayer.lineWidth = 2.0f;
    self.shapeLayer.lineCap = kCALineCapRound;
    self.shapeLayer.strokeColor = [UIColor colorWithRed:30.0/255.0 green:144.0/255.0 blue:255.0/255.0 alpha:1.0].CGColor;
    self.shapeLayer.strokeStart = 0.0f;
    //通过不断修改stroEnd的值,使形成像动画刷新的效果,也可以使用CAAnimation的方式,动画的显示出来,duration设置为你广告总时长就可以
    self.shapeLayer.strokeEnd = 0.0f;
    self.shapeLayer.path = self.path.CGPath;
    [self.layer addSublayer:self.shapeLayer];
    //修正坐标轴,逆时针旋转90度,从12点钟开始倒计时
    self.shapeLayer.transform =  CATransform3DRotate(CATransform3DIdentity, M_PI / 2, 0, 0, -1);
    //
    [self setTitle:NSLocalizedString(@"跳过", nil) forState:UIControlStateNormal];
    [self setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
    self.titleLabel.font = [UIFont systemFontOfSize:10.0];
}

/*改变进度条末端位置,循环调用实现进度条刷新*/
-(void)counting
{
    //strokeEnd的取值范围是0.0到1.0,所以超出1.0时截取
    CGFloat unit = self.tickTockInterval/(self.totalTime*1000.0);
    CGFloat f = self.shapeLayer.strokeEnd+unit;
    if (f > 1.0) {
        self.shapeLayer.strokeEnd = 1.0f;
    }else {
        self.shapeLayer.strokeEnd = f;
    }
}
@end
上一篇下一篇

猜你喜欢

热点阅读