說明:開發(fā)環(huán)境為XCode7 beta5
引導(dǎo)頁和廣告欄的制作都是基于UIScrollView,因此它們有許多相似的地方,不同的是引導(dǎo)頁有跳轉(zhuǎn)到其它頁面的功能,而廣告欄具有輪播的功能.
引導(dǎo)頁部分
-
打開XCode,創(chuàng)建一個(gè)新的工程,選擇Single View Application,點(diǎn)擊Next.
-
填寫工程名,Language選擇Swift,點(diǎn)擊Next.選擇一個(gè)位置存儲(chǔ)工程,點(diǎn)擊Create,完成工程的創(chuàng)建.
-
打開storyboard,取消勾選Use Size Classes,在彈出的提示框中,點(diǎn)擊Disable Size Classes,這樣設(shè)計(jì)面板會(huì)呈現(xiàn)iphone的大小.
-
從控件庫中拖出一個(gè)ScrollView到設(shè)計(jì)面板中,讓它鋪滿整個(gè)設(shè)計(jì)面板.
-
選中ScrollView給它增加一些約束,這樣做的結(jié)果是,在不同尺寸的iphone下,ScrollView都能鋪滿整個(gè)屏幕.
-
調(diào)整ScrollView的一些屬性:取消勾選滾動(dòng)條的顯示,勾選Paging Enable屬性,以及取消勾選Bounces屬性.
修改這些屬性之后,ScrollView會(huì)把水平方向和垂直方向的滾動(dòng)條隱藏掉,每一次滑動(dòng)ScrollView的內(nèi)容偏移量都會(huì)是一個(gè)屏幕的的寬度,沒有彈簧效果,(既是在滑動(dòng)到盡頭之后不能再繼續(xù)滑,松開手會(huì)自動(dòng)回彈的效果).
-
從控件庫拖一個(gè)Page Control到設(shè)計(jì)面板中,這時(shí)Page Control成為了ScrollView的子視圖,這不是想要的結(jié)果.從Document Outline中拖拽Page Control使它和ScrollView在同一層次上,都是View的子視圖.
-
對(duì)Page Control的屬性也做一些調(diào)整,改變它的Tint Color和Current Page Color.再對(duì)Page Control的尺寸和位置做一些修改.
完成后的效果圖如下
-
接著為Page Control添加一些約束,以確定Page Control的位置和大小.
-
打開輔助視圖.為ScrollView和Page Control生成相應(yīng)的outlet.選中ScrollView,按住ctrl鍵,按住鼠標(biāo)左鍵往輔助視圖中拖出一條藍(lán)色的箭頭,松開鼠標(biāo),填寫outlet的名字,點(diǎn)擊Connect就為控件生成了對(duì)應(yīng)outlet.用同樣的方法為Page Control生成outlet.這里生成的outlet分別為guideScrollView和pageControl.
-
打開資源文件夾,導(dǎo)入要用到的圖片資源.(其中3張用于引導(dǎo)頁,5張用于廣告欄,一張用作button的背景圖)
- 單擊ViewController.swift代碼文件,在其中添加代碼,實(shí)現(xiàn)引導(dǎo)頁的功能.
首先在viewDidLoad()函數(shù)的上方定義兩個(gè)常量,用來保存屏幕的寬高
let width = UIScreen.mainScreen().bounds.width
let height = UIScreen.mainScreen().bounds.height
接著在viewDidLoad()函數(shù)的下方定義一個(gè)函數(shù),用來對(duì)guideScrollView做一些配置.
func setGuidePages() {
// a. 設(shè)置scrollview的內(nèi)容大小
guideScrollView.contentSize = CGSizeMake(width * 3.0, height)
// b. 將引導(dǎo)頁圖片添加到scrollview中
for i in 1...3 {
let imageView = UIImageView(frame: CGRectMake(width * CGFloat(i - 1), 0, width, height))
imageView.image = UIImage(named: "guide\(i)")
guideScrollView.addSubview(imageView)
}
}
這里有3張引導(dǎo)頁而且是橫向滑動(dòng),所以把guideScrollView的內(nèi)容大小的寬度設(shè)置為3倍屏幕的寬度,高度設(shè)置為屏幕的高度.然后一個(gè)for循環(huán)創(chuàng)建3個(gè)imageView,將它水平排列,添加到guideScrollView中.
在viewDidLoad()函數(shù)中調(diào)用setGuidePages().
override func viewDidLoad() {
super.viewDidLoad()
setGuidePages()
}
到這一步為止,代碼文件類似于這樣.
import UIKit
class ViewController: UIViewController {
// 1. 拖拽生成控件的outlet
@IBOutlet weak var guideScrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
// 2. 定義兩個(gè)常量保存屏幕的寬高
let width = UIScreen.mainScreen().bounds.width
let height = UIScreen.mainScreen().bounds.height
override func viewDidLoad() {
super.viewDidLoad()
setGuidePages()
}
// 3. 配置guideScrollView
func setGuidePages() {
// a. 設(shè)置scrollview的內(nèi)容大小
guideScrollView.contentSize = CGSizeMake(width * 3.0, height)
// b. 將引導(dǎo)頁圖片添加到scrollview中
for i in 1...3 {
let imageView = UIImageView(frame: CGRectMake(width * CGFloat(i - 1), 0, width, height))
imageView.image = UIImage(named: "guide\(i)")
guideScrollView.addSubview(imageView)
}
}
}
運(yùn)行一下吧,看下有什么效果.
![](http://i3.tietuku.com/6bf2a440e275976b.png)
可以發(fā)現(xiàn)頁面可以左右滑動(dòng),pageControl卻沒有和當(dāng)前頁面對(duì)應(yīng)起來.為了解決這個(gè)問題,需要實(shí)現(xiàn)UIScrollView的一個(gè)代理方法,以此來獲得guideScrollView停止滑動(dòng)后的水平偏移量.
首先修改類的定義,讓ViewController遵循UIScrollViewDelegate協(xié)議.
class ViewController: UIViewController, UIScrollViewDelegate
在viewDidLoad()中添加一句代碼,添加到調(diào)用setGuidePages()函數(shù)之前就可以了.這句代碼把guideScrollView的代理人為當(dāng)前ViewController,那么UIScrollView的代理方法將由當(dāng)前的ViewController來執(zhí)行.
guideScrollView.delegate = self
接著實(shí)現(xiàn)一個(gè)代理方法,把它添加到setGuidePages()函數(shù)的下方.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// a. 獲得當(dāng)前顯示的頁面
let currentPage = Int(scrollView.contentOffset.x / width)
// b. 設(shè)置頁面控制器的當(dāng)前頁屬性
pageControl.currentPage = currentPage
}
這段代碼會(huì)在什么時(shí)候執(zhí)行呢??從代理方法的名字可以知道,在scrollView停止減速后會(huì)執(zhí)行這個(gè)代理方法.(停止減速,那么scrollView也停止滑動(dòng)了).
再運(yùn)行一次,看看效果.
![](http://i1.tietuku.com/c501d4559fc5eea6.png)
左右滑動(dòng)幾次,可以看到pageControl已經(jīng)和當(dāng)前顯示的引導(dǎo)頁對(duì)應(yīng)起來了.可以說引導(dǎo)頁的功能已經(jīng)完成了一半了.
接下來要在第3個(gè)引導(dǎo)頁上添加一個(gè)button,用來跳轉(zhuǎn)到主應(yīng)用.
在viewDidLoad()函數(shù)的上方定義一個(gè)button.
var goButton: UIButton!
編寫一個(gè)函數(shù),對(duì)goButton做一些配置,并把它添加到guideScrollView中.
func addButton() {
// a. 創(chuàng)建一個(gè)button,寬度為100,高度為35
goButton = UIButton(frame: CGRectMake(width * 2.0, height - 100.0, 100, 35))
// b. 讓button的中心點(diǎn)的橫坐標(biāo)位于第三個(gè)頁面的中心
goButton.center.x = self.view.center.x + width * 2.0
// c. 設(shè)置button的背景圖和標(biāo)題,以及標(biāo)題在不同狀態(tài)下的顏色
goButton.setBackgroundImage(UIImage(named: "bg"), forState: UIControlState.Normal)
goButton.setTitle("開始體驗(yàn)", forState: UIControlState.Normal)
goButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
goButton.setTitleColor(UIColor.lightGrayColor(), forState: UIControlState.Highlighted)
// d. 把button添加到guideScrollView中
guideScrollView.addSubview(goButton)
}
ok,接著在viewDidLoad()中調(diào)用addButton()
運(yùn)行一遍,看下效果.
![](http://i1.tietuku.com/d536c3d028eee584.png)
為了讓goButton有一個(gè)淡出的效果,把scrollViewDidEndDecelerating(scrollView: UIScrollView)做如下修改.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
// a. 獲得當(dāng)前顯示的頁面
let currentPage = Int(scrollView.contentOffset.x / width)
if currentPage == 2 {
UIView.animateWithDuration(1.5, animations: { () -> Void in
self.goButton.layer.opacity = 1
})
}
else {
UIView.animateWithDuration(1.5, animations: { () -> Void in
self.goButton.layer.opacity = 0
})
}
// b. 設(shè)置頁面控制器的當(dāng)前頁屬性
pageControl.currentPage = currentPage
}
頁面的下標(biāo)從0開始,if語句的作用判斷當(dāng)前是否滑到了第3個(gè)頁面,是的話將goButton的透明度設(shè)置為1,讓它呈現(xiàn)出來,否則把goButton的透明度設(shè)置為0,將它隱藏.
為了在點(diǎn)擊goButton可以跳轉(zhuǎn)到新的頁面,需要另外一個(gè)ViewController來承載新的頁面.
打開storyboard拖出一個(gè)新的ViewController
![](http://i3.tietuku.com/ae2a63480bfc557f.png)
選中新添加的ViewController,給它設(shè)置一個(gè)Storyboard ID,通過這個(gè)ID,可以用代碼的方式獲取到這個(gè)ViewController.
![](http://i3.tietuku.com/2716d6adc5cbd4cf.png)
接著創(chuàng)建一個(gè)新的文件,選擇Cocoa Touch Class,點(diǎn)擊Next
![](http://i3.tietuku.com/918983d1b9da3818.png)
創(chuàng)建一個(gè)類,命名為MainPageViewController,繼承自UIViewController
![](http://i3.tietuku.com/478a94c23e6fe834.png)
然后回到storyboard,選中新添加的ViewController,讓它綁定到新創(chuàng)建的類.
![](http://i3.tietuku.com/70259c4813d1aefb.png)
ok,現(xiàn)在打開ViewController.swift代碼文件,添加相應(yīng)的代碼,實(shí)現(xiàn)跳轉(zhuǎn)的功能.
在最后一個(gè)花括號(hào)的上方,定義一個(gè)函數(shù)
func goMainPage(button: UIButton) {
let mainPageVC = storyboard!.instantiateViewControllerWithIdentifier("mainPage")
self.presentViewController(mainPageVC, animated: true, completion: nil)
}
這段代碼的作用是,通過storyboard初始化剛剛創(chuàng)建的MainPageViewController,然后將它呈現(xiàn)出來.
為了能夠執(zhí)行到這段代碼,讓goButton和這段代碼做一個(gè)綁定,當(dāng)點(diǎn)擊goButton時(shí)將會(huì)把MainPageViewController呈現(xiàn)出來.把下面這句代碼添加到addButton()函數(shù)中,添加到addSubview之前.
goButton.addTarget(self, action: "goMainPage:", forControlEvents: UIControlEvents.TouchUpInside)
ok,試著運(yùn)行一遍,滑動(dòng)到第3個(gè)頁面,按鈕漸漸淡出,點(diǎn)擊goButton,可以跳轉(zhuǎn)到新的頁面.現(xiàn)在這個(gè)頁面是空白的,后面一點(diǎn)會(huì)為它加上廣告欄.
導(dǎo)航頁一般是在第一次啟動(dòng)APP時(shí)出現(xiàn),以后啟動(dòng)之后就不會(huì)看到引導(dǎo)頁了.那么接下來要做的就是判斷APP是不是第一次啟動(dòng),是的話展現(xiàn)引導(dǎo)頁,不是的話,直接跳轉(zhuǎn)到主頁面.
打開AppDelegate.swift文件,在func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 函數(shù)中添加以下代碼.
let firstLuanch = !NSUserDefaults.standardUserDefaults().boolForKey("notFirstLuanch")
if firstLuanch == true {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "notFirstLuanch")
}
else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainPageVC = storyboard.instantiateViewControllerWithIdentifier("mainPage")
window?.rootViewController = mainPageVC
}
NSUserDefaults是用來存儲(chǔ)一些簡單數(shù)據(jù)的,以鍵值對(duì)的形式保存在程序中.
boolForKey()的作用是通過一個(gè)key來獲取到與這個(gè)key對(duì)應(yīng)的值,而且這個(gè)值得類型為Bool類型.
這段代碼首先通過"notFirstLuanch"鍵獲取到一個(gè)Bool值,因?yàn)閺膩頉]有給"notFirstLuanch" key賦值過,第一行代碼或默認(rèn)返回false,對(duì)它進(jìn)行取反操作,常量firstLuanch的值就被設(shè)置為true了,表明是第一次啟動(dòng).
接著是一個(gè)if語句,第一次啟動(dòng)時(shí)將"notFirstLuanch"鍵對(duì)應(yīng)的值設(shè)置為true,那么以后啟動(dòng)時(shí),firstLuanch的值將會(huì)是false.
當(dāng)firstLuanch的值是false時(shí),首先獲取到storyboard,再通過storyboard實(shí)例化一個(gè)MainPageViewController,把它命名為mainPageVC,并讓它成為window的根視圖控制器(一開始呈現(xiàn)的頁面為rootViewController),那么呈現(xiàn)出來的頁面將會(huì)是后面添加的MainPageViewController.
現(xiàn)在運(yùn)行下試試,和以前沒有什么不同. ok,停掉程序,再次運(yùn)行,這次可以看到程序直接進(jìn)入了主界面,跳過了引導(dǎo)頁的部分.
把程序從模擬器上刪掉,然后重新運(yùn)行一遍,這次又可以看到引導(dǎo)頁了.
![](http://i3.tietuku.com/226996342c4aad1e.png)
引導(dǎo)頁部分到現(xiàn)在就完成了,接下來是廣告欄部分.
廣告欄部分
廣告欄在storyboard的配置部分和引導(dǎo)頁的部分是類似的,這里就不重復(fù)了,下面是配置完的效果圖.
![](http://i3.tietuku.com/0824859eb6973003.png)
MainPageViewController.swift代碼文件的內(nèi)容現(xiàn)在如下所示.
import UIKit
class MainPageViewController: UIViewController, UIScrollViewDelegate {
// 1. 與控件綁定的outlet
@IBOutlet weak var bannerScrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
// 2. 指示當(dāng)前頁面變量
var currenrPage = 0
override func viewDidLoad() {
super.viewDidLoad()
configureBanner()
}
// 3. 配置廣告欄
func configureBanner() {
let width = self.view.frame.width
let height = width / 32.0 * 13
bannerScrollView.delegate = self
bannerScrollView.contentSize = CGSizeMake(width * 5.0, height)
for i in 1...5 {
let imageView = UIImageView(frame: CGRectMake(width * CGFloat(i - 1), 0, width, height))
imageView.image = UIImage(named: "banner\(i)")
bannerScrollView.addSubview(imageView)
}
}
// 4. 實(shí)現(xiàn)UIScrollView的代理方法
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
currenrPage = Int(scrollView.contentOffset.x / self.view.frame.width)
pageControl.currentPage = currenrPage
}
}
前期代碼和引導(dǎo)頁部分的非常相似,只是多了一個(gè)記錄當(dāng)前頁面的變量.
接下來要實(shí)現(xiàn)的是,廣告欄的輪播功能.為此需要一個(gè)定時(shí)器,來讓廣告欄以一定的時(shí)間間隔播放.
首先在在viewDidLoad()函數(shù)的上方定義一個(gè)定時(shí)器變量
var timer: NSTimer!
在scrollViewDidEndDecelerating代理方法的下方,定義兩個(gè)函數(shù),一個(gè)用來啟動(dòng)定時(shí)器,一個(gè)用來移除定時(shí)器.
func addTimer() {
// 構(gòu)造一個(gè)定時(shí)器,每隔3秒調(diào)用nextBanner()函數(shù).這個(gè)操作會(huì)重復(fù)執(zhí)行
timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: "nextBanner", userInfo: nil, repeats: true)
}
func removeTimer() {
// 讓定時(shí)器不可用
timer.invalidate()
}
接著需要實(shí)現(xiàn)播放下一則廣告的函數(shù),這個(gè)函數(shù)會(huì)被定時(shí)器重復(fù)調(diào)用.把這個(gè)函數(shù)添加到最后一個(gè)花括號(hào)的上方.
func nextBanner() {
if currentPage == 4 {
currentPage = 0
}
else {
currentPage++
}
pageControl.currentPage = currentPage
let offset = CGFloat(currentPage) * self.view.frame.width
bannerScrollView.setContentOffset(CGPoint(x: offset, y: 0), animated: true)
}
ok,在viewDidLoad()函數(shù)中調(diào)用addTimer()
override func viewDidLoad() {
super.viewDidLoad()
configureBanner()
// 啟用定時(shí)器
addTimer()
}
運(yùn)行看下效果吧!!
![](http://i3.tietuku.com/a2f19f312c5e3f85.png)
可以看到廣告輪播的效果已經(jīng)實(shí)現(xiàn)了.可是還有一個(gè)問題,就是在用戶滑動(dòng)的時(shí)候,定時(shí)器還在計(jì)時(shí),這樣可能出現(xiàn)的結(jié)果是,當(dāng)用戶滑到上一頁時(shí),它又很快的跳到了下一頁.因此需要在用戶滑動(dòng)廣告欄時(shí),停掉定時(shí)器.
再實(shí)現(xiàn)UIScrollView的一個(gè)代理方法,把這個(gè)代理方法添加到scrollViewDidEndDecelerating代理方法的下方.
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
removeTimer()
}
這個(gè)代理方法,在用戶開始滑動(dòng)scrollView是被調(diào)用,在這個(gè)代理方法中讓定時(shí)器不可用.
那要什么時(shí)候恢復(fù)定時(shí)呢??在用戶的手指離開廣告欄之后就可以了.接著添加以下代理方法.
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addTimer()
}
完整的代碼文件如下所示
import UIKit
class MainPageViewController: UIViewController, UIScrollViewDelegate {
// 1. 與控件綁定的outlet
@IBOutlet weak var bannerScrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
// 2. 指示當(dāng)前頁面變量
var currentPage = 0
// 5. 定義一個(gè)定時(shí)器變量
var timer: NSTimer!
override func viewDidLoad() {
super.viewDidLoad()
configureBanner()
addTimer()
}
// 3. 配置廣告欄
func configureBanner() {
let width = self.view.frame.width
let height = width / 32.0 * 13
bannerScrollView.delegate = self
bannerScrollView.contentSize = CGSizeMake(width * 5.0, height)
for i in 1...5 {
let imageView = UIImageView(frame: CGRectMake(width * CGFloat(i - 1), 0, width, height))
imageView.image = UIImage(named: "banner\(i)")
bannerScrollView.addSubview(imageView)
}
}
// 4. 實(shí)現(xiàn)UIScrollView的代理方法
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
currentPage = Int(scrollView.contentOffset.x / self.view.frame.width)
pageControl.currentPage = currentPage
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
removeTimer()
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addTimer()
}
// 6. 使用定時(shí)器實(shí)現(xiàn)廣告輪播
func addTimer() {
// 構(gòu)造一個(gè)定時(shí)器,每隔3秒調(diào)用nextBanner()函數(shù).這個(gè)操作會(huì)重復(fù)執(zhí)行
timer = NSTimer.scheduledTimerWithTimeInterval(3.0, target: self, selector: "nextBanner", userInfo: nil, repeats: true)
}
func removeTimer() {
// 讓定時(shí)器不可用
timer.invalidate()
}
// 7. 呈現(xiàn)下一個(gè)廣告
func nextBanner() {
if currentPage == 4 {
currentPage = 0
}
else {
currentPage++
}
pageControl.currentPage = currentPage
let offset = CGFloat(currentPage) * self.view.frame.width
bannerScrollView.setContentOffset(CGPoint(x: offset, y: 0), animated: true)
}
}