做这个东西的话,其实主要是因为一件事,我会比较经常食用手机迅雷下载电影,每次开启迅雷,都会默认来一段广告,这种强制的让使用者看广告的行为虽然让人很讨厌,但是本着好奇就认真挖掘的原则,看了一下网上的介绍,再自己实践了一下。
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
网友评论