目前市場上很多APP(如淘寶、美團、微博、UC)在啟動圖載入完畢後,還會顯示幾秒的廣告,右上角都有個跳過按鈕可以選擇立即跳過這個廣告,有的APP在點選廣告頁之後還會進入一個廣告頁。 他們玩的樂此不疲,產品汪們見了自然也是不會放過這個效果:
思路如下:
- 封裝廣告頁, 展現跳過按鈕實現倒數計時功能 2.判斷廣告頁面是否更新。非同步下載新圖片, 刪除老圖片 3.廣告頁顯示 4.廣告頁點選後展示頁
廢話少說,這邊先上核心程式碼了:
###一. 封裝廣告頁, 展現跳過按鈕實現倒數計時功能
ZLAdvertView.h: 先封裝出來廣告頁,露出顯示廣告頁面方法和圖片路徑
#import <UIKit/UIKit.h>
#define kscreenWidth [UIScreen mainScreen].bounds.size.width
#define kscreenHeight [UIScreen mainScreen].bounds.size.height
#define kUserDefaults [NSUserDefaults standardUserDefaults]
static NSString *const adImageName = @"adImageName";
static NSString *const adUrl = @"adUrl";
@interface ZLAdvertView : UIView
/**
* 顯示廣告頁面方法
*/
- (void)show;
/**
* 圖片路徑
*/
@property (nonatomic, copy) NSString *filePath;
@end
複製程式碼
ZLAdvertView.m:
核心程式碼見下面程式碼塊:
#import "ZLAdvertView.h"
@interface ZLAdvertView ()
@property (nonatomic, strong) UIImageView *adView;
@property (nonatomic, strong) UIButton *countBtn;
@property (nonatomic, strong) NSTimer *countTimer;
@property (nonatomic, assign) int count;
@end
// 廣告顯示的時間
static int const showtime = 3;
複製程式碼
1. 為廣告頁面新增一個點選手勢,跳轉到廣告頁面.
@implementation ZLAdvertView
- (NSTimer *)countTimer {
if (!_countTimer) {
_countTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDown) userInfo:nil repeats:YES];
}
return _countTimer;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 1.廣告圖片
_adView = [[UIImageView alloc] initWithFrame:frame];
_adView.userInteractionEnabled = YES;
_adView.contentMode = UIViewContentModeScaleAspectFill;
_adView.clipsToBounds = YES;
// 為廣告頁面新增一個點選手勢,跳轉到廣告頁面
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pushToAd)];
[_adView addGestureRecognizer:tap];
// 2.跳過按鈕
CGFloat btnW = 60;
CGFloat btnH = 30;
_countBtn = [[UIButton alloc] initWithFrame:CGRectMake(kscreenWidth - btnW - 24, btnH, btnW, btnH)];
[_countBtn addTarget:self action:@selector(removeAdvertView) forControlEvents:UIControlEventTouchUpInside];
[_countBtn setTitle:[NSString stringWithFormat:@"跳過%d", showtime] forState:UIControlStateNormal];
_countBtn.titleLabel.font = [UIFont systemFontOfSize:15];
[_countBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_countBtn.backgroundColor = [UIColor colorWithRed:38 /255.0 green:38 /255.0 blue:38 /255.0 alpha:0.6];
_countBtn.layer.cornerRadius = 4;
[self addSubview:_adView];
[self addSubview:_countBtn];
}
return self;
}
- (void)setFilePath:(NSString *)filePath {
_filePath = filePath;
_adView.image = [UIImage imageWithContentsOfFile:filePath];
}
- (void)pushToAd {
[self removeAdvertView];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ZLPushToAdvert" object:nil userInfo:nil];
}
複製程式碼
2. 廣告頁面的跳過按鈕倒數計時功能可以通過定時器或者GCD實現(這裡以廣告倒數計時3s 做例子)
- (void)countDown {
_count --;
[_countBtn setTitle:[NSString stringWithFormat:@"跳過%d",_count] forState:UIControlStateNormal];
if (_count == 0) {
[self removeAdvertView];
}
}
// 廣告頁面的跳過按鈕倒數計時功能可以通過定時器或者GCD實現
- (void)show {
// 倒數計時方法1:GCD
// [self startCoundown];
// 倒數計時方法2:定時器
[self startTimer];
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:self];
}
// 定時器倒數計時
- (void)startTimer {
_count = showtime;
[[NSRunLoop mainRunLoop] addTimer:self.countTimer forMode:NSRunLoopCommonModes];
}
// GCD倒數計時
- (void)startCoundown {
__weak __typeof(self) weakSelf = self;
__block int timeout = showtime + 1; //倒數計時時間 + 1
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _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, ^{
if(timeout <= 0){ //倒數計時結束,關閉
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf removeAdvertView];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[_countBtn setTitle:[NSString stringWithFormat:@"跳過%d",timeout] forState:UIControlStateNormal];
});
timeout--;
}
});
dispatch_resume(_timer);
}
// 移除廣告頁面
- (void)removeAdvertView {
// 停掉定時器
[self.countTimer invalidate];
self.countTimer = nil;
[UIView animateWithDuration:0.3f animations:^{
self.alpha = 0.f;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}
@end
複製程式碼
###二. 判斷廣告頁面是否更新。非同步下載新圖片, 刪除老圖片 因為廣告頁的內容要實時顯示,在無網路狀態或者網速緩慢的情況下不能延遲載入,或者等到首頁出現了再載入廣告頁。所以這裡不採用網路請求廣告介面去獲取圖片地址然後載入圖片的方式,而是先將圖片非同步下載到本地,並儲存圖片名,每次開啟app時先根據本地儲存的圖片名查詢沙盒中是否存在該圖片,如果存在,則顯示廣告頁。 在AppDelegate.m 裡:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[HomeViewController alloc] init]];
[self.window makeKeyAndVisible];
// 設定啟動頁廣告
[self setupAdvert];
return YES;
}
複製程式碼
1.判斷沙盒中是否存在廣告圖片,如果存在,直接顯示
/**
* 設定啟動頁廣告
*/
- (void)setupAdvert {
// 1.判斷沙盒中是否存在廣告圖片,如果存在,直接顯示
NSString *filePath = [self getFilePathWithImageName:[kUserDefaults valueForKey:adImageName]];
BOOL isExist = [self isFileExistWithFilePath:filePath];
if (isExist) { // 圖片存在
ZLAdvertView *advertView = [[ZLAdvertView alloc] initWithFrame:self.window.bounds];
advertView.filePath = filePath;
[advertView show];
}
// 2.無論沙盒中是否存在廣告圖片,都需要重新呼叫廣告介面,判斷廣告是否更新
[self getAdvertisingImage];
}
/**
* 判斷檔案是否存在
*/
- (BOOL)isFileExistWithFilePath:(NSString *)filePath {
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory = FALSE;
return [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
}
複製程式碼
2.無論沙盒中是否存在廣告圖片,都需要重新呼叫獲取廣告介面,判斷廣告是否更新
/**
* 初始化廣告頁面
*/
- (void)getAdvertisingImage {
// TODO 請求廣告介面
// 這裡原本應該採用廣告介面,現在用一些固定的網路圖片url代替
NSArray *imageArray = @[
@"https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/super/whfpf%3D425%2C260%2C50/sign=a4b3d7085dee3d6d2293d48b252b5910/0e2442a7d933c89524cd5cd4d51373f0830200ea.jpg",
@"https://ss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/super/whfpf%3D425%2C260%2C50/sign=a41eb338dd33c895a62bcb3bb72e47c2/5fdf8db1cb134954a2192ccb524e9258d1094a1e.jpg",
@"http://c.hiphotos.baidu.com/image/w%3D400/sign=c2318ff84334970a4773112fa5c8d1c0/b7fd5266d0160924c1fae5ccd60735fae7cd340d.jpg"
];
NSString *imageUrl = imageArray[arc4random() % imageArray.count];
// 獲取圖片名:43-130P5122Z60-50.jpg
NSArray *stringArr = [imageUrl componentsSeparatedByString:@"/"];
NSString *imageName = stringArr.lastObject;
// 拼接沙盒路徑
NSString *filePath = [self getFilePathWithImageName:imageName];
BOOL isExist = [self isFileExistWithFilePath:filePath];
if (!isExist){ // 如果該圖片不存在,則刪除老圖片,下載新圖片
[self downloadAdImageWithUrl:imageUrl imageName:imageName];
}
}
複製程式碼
3.非同步下載新圖片, 刪除老圖片
/**
* 下載新圖片
*/
- (void)downloadAdImageWithUrl:(NSString *)imageUrl imageName:(NSString *)imageName {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]];
UIImage *image = [UIImage imageWithData:data];
NSString *filePath = [self getFilePathWithImageName:imageName]; // 儲存檔案的名稱
if ([UIImagePNGRepresentation(image) writeToFile:filePath atomically:YES]) {// 儲存成功
NSLog(@"儲存成功");
[self deleteOldImage];
[kUserDefaults setValue:imageName forKey:adImageName];
[kUserDefaults synchronize];
// 如果有廣告連結,將廣告連結也儲存下來
}else{
NSLog(@"儲存失敗");
}
});
}
/**
* 刪除舊圖片
*/
- (void)deleteOldImage {
NSString *imageName = [kUserDefaults valueForKey:adImageName];
if (imageName) {
NSString *filePath = [self getFilePathWithImageName:imageName];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:filePath error:nil];
}
}
/**
* 根據圖片名拼接檔案路徑
*/
- (NSString *)getFilePathWithImageName:(NSString *)imageName {
if (imageName) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:imageName];
return filePath;
}
return nil;
}
複製程式碼
###三. 廣告頁顯示。 廣告頁的顯示程式碼可以放在AppDeleate中,也可以放在首頁的控制器中。如果程式碼是在AppDelegate中,可以通過傳送通知的方式,讓首頁push到廣告詳情頁.
首頁控制器HomeViewController.m:
#import "HomeViewController.h"
#import "ZLAdvertViewController.h"
@interface HomeViewController ()
@end
@implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"首頁";
self.view.backgroundColor = [UIColor greenColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pushToAd) name:@"ZLPushToAdvert" object:nil];
}
// 進入廣告連結頁
- (void)pushToAd {
ZLAdvertViewController *adVc = [[ZLAdvertViewController alloc] init];
[self.navigationController pushViewController:adVc animated:YES];
}
@end
複製程式碼
###四. 廣告頁點選後展示頁。 如果點選廣告需要跳轉廣告詳情頁面,那麼廣告連結地址也需要用NSUserDefaults儲存。注意:廣告詳情頁面是從首頁push進去的 廣告連結頁ZLAdvertViewController.h :
// 廣告連結頁
#import <UIKit/UIKit.h>
@interface ZLAdvertViewController : UIViewController
@property (nonatomic, copy) NSString *adUrl;
@end
複製程式碼
ZLAdvertViewController.m :
#import "ZLAdvertViewController.h"
@interface ZLAdvertViewController ()
@property (nonatomic, strong) UIWebView *webView;
@end
@implementation ZLAdvertViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"點選進入廣告連結";
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.backgroundColor = [UIColor whiteColor];
if (!self.adUrl) {
self.adUrl = @"http://www.baidu.com";
}
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.adUrl]];
[_webView loadRequest:request];
[self.view addSubview:_webView];
}
- (void)setAdUrl:(NSString *)adUrl {
_adUrl = adUrl;
}
@end
複製程式碼
注意: 廣告頁面的底部和啟動圖的底部一般都是相同的,給使用者的錯覺就是啟動圖載入完之後把廣告圖放在了啟動圖上,而且不能有偏差。所以我們開發要圖時需要提醒美工在製作廣告圖的時候要注意下。
如果需要啟動動態頁跳過的這種啟動頁方案 ,請移步: iOS-啟動動態頁跳過設計思路