很多app在啟動圖加載完畢后,還會顯示幾秒的廣告,有個跳過按鈕可以跳過這個廣告,有的app在點擊廣告頁之后還會進入一個廣告頁面,點擊返回進入首頁。今天我們就來開發一個廣告頁面,效果如下。
思路
1.廣告頁加載:廣告頁的內容要實時顯示,在沒網絡或者網絡很差的情況下依然可以顯示。所以我的做法是通過接口獲取圖片鏈接等一些信息,然后將圖片異步下載到本地,并保存圖片名,每次打開app時先根據本地存儲的圖片名查找沙盒中是否存在該圖片,如果存在,則顯示廣告頁。
2.檢測廣告頁面是否更新。無論本地是否存在廣告圖片,每次打開APP都重新調用獲取廣告圖片鏈接等信息的接口,根據圖片名稱或者其他唯一標識等方法判斷廣告是否更新,如果圖片的唯一標識與本地保存的信息不一致,則重新下載新圖片,并覆蓋舊圖片。
3.廣告頁點擊。如果點擊廣告需要跳轉廣告詳情頁面,我的做法是將獲取廣告信息的接口返回的數據全部保存在本地,點擊的時候從本地取出要廣告的鏈接即可,廣告詳情頁面是從首頁跳轉的。
4.廣告頁的顯示代碼可以放在AppDeleate中或者放在UITabbarController
的控制器中。如果代碼是在AppDelegate中,可以通過發送通知的方式,讓首頁push到廣告詳情頁,如果代碼實在UITabbarController里的直接在UITabbarController里處理即可,我做法是直接將代碼放在UITabbarController里。
5.主要邏輯。用戶第一次打開APP的時候不顯示廣告,在這個時候去調用廣告圖片接口,將數據保存在本下載圖片保存在沙盒中,用戶第二打開APP的時候照樣調用廣告接口,并將調用接口返回的數據的唯一標識與之前本地保存的廣告數據的唯一標識進行比較,如果不一樣則進行現在圖片并保存,用于下一次啟動APP時顯示。
注意:
一般廣告頁面的底部和啟動圖的底部一般都是相同的,這樣給用戶的感覺就是一直是同一個頁面,而不是跳轉到另一頁面顯示的。
代碼:
1、自定義廣告頁面:
import UIKit
@objc protocol AdvertViewDelegate {
@objc optional
func onclickAdvertView(view: AdvertView)
}
class AdvertView: UIImageView {
private var btn = UIButton(type: .custom)
private var times: Int = 0
private weak var delegate: AdvertViewDelegate?
// 在global線程里創建一個時間源
private let codeTimer = DispatchSource.makeTimerSource(queue:DispatchQueue.global())
class func addAdvertView(supView: UIView, image: UIImage, times: Int, frame: CGRect, delegate: Any) {
let advertView = AdvertView(frame: frame)
supView.addSubview(advertView)
advertView.times = times;
advertView.image = image;
advertView.startCoundown()
advertView.delegate = delegate as? AdvertViewDelegate
}
override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = true
addSubview(btn)
btn.backgroundColor = UIColor.black
btn.alpha = 0.8
btn.layer.cornerRadius = 5
btn.titleLabel?.font = UIFont.systemFont(ofSize: 12)
btn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
let tap = UITapGestureRecognizer(target: self, action: #selector(clickView))
addGestureRecognizer(tap)
}
@objc private func clickView() {
delegate?.onclickAdvertView?(view: self)
}
@objc private func btnClick() {
codeTimer.cancel()
UIView.animate(withDuration: 1.0, animations: {
self.alpha = 0.0
}, completion: { (true) in
self.removeFromSuperview()
})
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func startCoundown() {
btn.setTitle("跳過\(times)", for: .normal)
var timeCount = times + 1
// 設定這個時間源是每秒循環一次,立即開始
codeTimer.scheduleRepeating(deadline: .now(), interval: .seconds(1))
// 設定時間源的觸發事件
codeTimer.setEventHandler(handler: {
// 每秒計時一次
timeCount = timeCount - 1
// 時間到了取消時間源
if timeCount <= 0 {
self.codeTimer.cancel()
DispatchQueue.main.async {
UIView.animate(withDuration: 1.0, animations: {
self.alpha = 0.0
}, completion: { (true) in
self.removeFromSuperview()
})
}
}
// 返回主線程處理一些事件,更新UI等等
DispatchQueue.main.async {
self.btn.setTitle("跳過 \(timeCount)", for: .normal)
}
})
// 啟動時間源
codeTimer.resume()
}
override func layoutSubviews() {
super.layoutSubviews()
let y: CGFloat = 20.0
let width: CGFloat = 70.0
let height: CGFloat = 30.0
let x: CGFloat = screenWidth - width - 10.0
btn.frame = CGRect.init(x: x, y: y, width: width, height: height)
}
deinit {
}
}
2、UITabbarController主要代碼
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//從沙盒中取出廣告圖片
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imagePath = "\(path!)/\(AdvertImage).png"
guard let image = UIImage.init(contentsOfFile: imagePath) else{
return
}
AdvertView.addAdvertView(supView: self.view, image: image, times: 10, frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight), delegate: self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
getImage()
}
// MARK: - 網絡請求
extension KKMainTabBarController {
/// 下載圖片
func downImage(url: URL) {
SDWebImageManager.shared().downloadImage(with: url, options: SDWebImageOptions(rawValue: 0), progress: nil, completed: { (image, error, type, animated, url) in
guard let image = image else{
return
}
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imageData = UIImageJPEGRepresentation(image, 0.5)
guard let imgData = imageData else{
return
}
let imagepath = "\(path!)/\(AdvertImage).png"
NSData(data: imgData).write(toFile: imagepath, atomically: true)
})
}
/// 調用廣告接口
func getImage() {
KKAFNetWorking.sharedManager.reqeust(url: "http://192.168.2.32/ceshi/public/index.php?s=admin/File/getAdvertImage", method: "GET") { (obj) in
guard let obj = obj else{
return
}
guard let status = obj["status"] as? String else{
return
}
if status == "200" {
guard let array = obj["data"] as? [[String: Any]] else{
return
}
guard let data = array.first else{
return
}
guard let currentid = (data["imageUrl"] as? String) else{
return
}
let userdefault = UserDefaults.standard
let dict = userdefault.value(forKey: AdvertImage) as? [String: Any]
userdefault.set(data, forKey: AdvertImage)
userdefault.synchronize()
if dict != nil {
let orgid = dict!["imageUrl"]! as! String
if currentid != orgid {
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}else {//判斷圖片是否存在,
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let imagePath = "\(path!)/\(AdvertImage).png"
if ( FileManager.default.fileExists(atPath: imagePath) == false) {
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}
}
}else{
let url = URL(string: "http://192.168.2.32/ceshi/public/uploads/\(currentid)")
self.downImage(url: url!)
}
}else{
return
}
}
}
}
獲取圖片接口是我自己寫的,外網訪問不了??????
以下是接口返回的數據
{
data = (
{
"add_time" = "2017-05-13 14:32:54";
id = 2;
imageUrl = "20170422/3.png";
}
);
message = "\U6570\U636e\U83b7\U53d6\U6210\U529f";
status = 200;
}