在導航過程當中,有時候須要放棄主要任務而作其餘次要任務,而後在返回到次要任務,這個次要任務就是在模態視圖中完成的,如註冊中主要任務是登陸後進入主界面,若是用戶沒有註冊,就要先去註冊,註冊是次要任務,當用戶註冊完成後,它會關閉註冊視圖,回到登陸界面繼續進行主要任務。web
默認狀況下,模態視圖是從屏幕下方滑出來的。swift
負責控制器模態視圖的控制器稱爲模態視圖控制器,它並非一個專門的類,它能夠是前面提到的控制器的子類。負責主要任務視圖的控制器稱爲主視圖控制器。在UICOntrollerView中,主要有以下兩個方法:app
-present():呈現視圖ide
-dismiss():關閉視圖post
在呈現模態視圖時有兩種方式:一是經過使用UIViewController的present方法實現;二是經過故事板的「過渡」(Segue)實現。url
下面咱們經過登陸案例來介紹模態視圖spa
建立一個iOS工程,將當前控制器嵌入到一個導航控制器中,具體步驟是:在故事板中選擇View Controller,而後點擊Xcode菜單欄Editor-Embed In-Navigation Controller菜單就會自動建立一個導航視圖設計
點擊導航欄,將導航欄的標題設爲登陸,而後從對象庫中拖入Lable、TextField、Button等控件code
接下來設計第二個界面,先從對象庫中拖入一個View Controller到設計界面中,而後參考步驟1將該視圖控制器嵌入到導航控制器中,修改該導航欄標題爲註冊,而後從對象庫中拖入兩個Bar Button Item到導航欄兩邊,分別設置identifier屬性爲Cancel和Saveserver
接下來須要在登陸場景和註冊場景建立一個過渡,按住control鍵,從登陸界面的註冊按鈕拖鼠標到註冊導航控制器,而後鬆開鼠標,在彈出的視圖框中選擇Present Modally菜單;它是模態類型的過渡
最後,添加註冊控制器類,建立一個類RegisterViewController集成UIViewController,而後回到故事板中將註冊視圖的Class選擇爲RegisterViewController
ViewController.swift
// // ViewController.swift // ModalViewSample // // Created by Michael on 2016/11/9. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var mUserName: UITextField! override func viewDidLoad() { super.viewDidLoad() // 註冊消息 NotificationCenter.default.addObserver(self, selector: #selector(self.register(_ :)), name: NSNotification.Name(rawValue: "RegisterCompletion"), object: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. NotificationCenter.default.removeObserver(self, name: NSNotification.Name.init(rawValue: "RegisterCompletion"), object: nil) } func register(_ notification : Notification) { let text = notification.userInfo?["username"] as? String mUserName.text = text! NSLog("%@",text!) } }
RegisterViewController.swift
// // RegisterViewController.swift // ModalViewSample // // Created by Michael on 2016/11/9. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class RegisterViewController: UIViewController { @IBOutlet weak var mName: UITextField! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func save(_ sender: Any) { let userInfo = ["username":self.mName.text!] //發送消息 NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "RegisterCompletion"), object: nil, userInfo: userInfo) self.dismiss(animated: true, completion: { }) } @IBOutlet weak var save: UIBarButtonItem! @IBAction func cancel(_ sender: Any) { self.dismiss(animated: true, completion: { }) } }
基於分屏導航是平鋪導航的主要實現方式,涉及的主要控件有分屏控件UIPageControll和屏幕滾動視圖UIScrollView,通常不超過10屏
建立iOS工程,從對象庫中拖入UIPageControll和UIScrollView到故事板中,並將其放到合適的位置,UIPageControll放在靠底部,UIScrollView全屏顯示,將視圖的背景設爲黑色
選中UIScrollView的屬性檢查器,設置不顯示Scroll View的Indicator,同時選擇滾動Scrolling Enable和分屏Paging Enable。分屏屬性是Scroll View每次滑動時翻一屏
選擇Page Controll的屬性檢查器,設置Pages中的of pages總屏數爲3,Current當前位置爲0,並修改其寬度爲300,它的高度是不能修改的。
最後爲這兩個控件定義輸出口並鏈接註冊到ViewController類中,爲Page Controll控件定義響應屏幕變化事件的方法。-changPage
// // ViewController.swift // PageControlNavigation // // Created by Michael on 2016/11/10. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class ViewController: UIViewController,UIScrollViewDelegate { @IBOutlet weak var mScrollView: UIScrollView! @IBOutlet weak var mPageControl: UIPageControl! var mImage1: UIImageView! var mImage2: UIImageView! var mImage3: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.mScrollView.delegate = self self.mScrollView.contentSize = CGSize(width: self.view.frame.size.width * 3, height: self.mScrollView.frame.size.height) self.mScrollView.frame = self.view.frame self.mImage1 = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 480)) self.mImage1.image = UIImage(named: "達芬奇-蒙娜麗莎") self.mScrollView.addSubview(mImage1) self.mImage2 = UIImageView(frame: CGRect(x: self.view.frame.size.width, y: 0, width: self.view.frame.size.width, height: 480)) self.mImage2.image = UIImage(named: "羅丹-思想者") self.mScrollView.addSubview(mImage2) self.mImage3 = UIImageView(frame: CGRect(x: self.view.frame.size.width * 2, y: 0, width: self.view.frame.size.width, height: 480)) self.mImage3.image = UIImage(named: "保羅克利-肖像") self.mScrollView.addSubview(mImage3) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } //UIPageControll事件處理 @IBAction func changePage(_ sender: Any) { UIView.animate(withDuration: 0.3, animations: { let whichPage = self.mPageControl.currentPage //設置內容視圖座標原點與屏幕滾動視圖坐原點的偏移量 self.mScrollView.contentOffset = CGPoint(x: 320 * whichPage, y: 0) }) } //屏幕滾動視圖事件處理方法å func scrollViewDidScroll(_ scrollView: UIScrollView) { let offset = scrollView.contentOffset self.mPageControl.currentPage = Int(offset.x) / 320 } }
在iOS5之後,咱們可使用分頁控制器UIPageViewController構建相似於電子書效果的應用。
分頁控制器須要放置在一個父視圖控制器中,在分頁控制器下面還要有子視圖控制器,每一個子視圖控制器對應一個頁面。
UIPageViewController沒有對應的視圖,咱們須要使用代碼來實現;須要在UIPageViewController所在的控制器實現UIPageViewControllerDelegate和UIPageViewControllerDataSource協議,UIPageViewControllerDataSource數據源協議必需要實現的方法有如下兩個:
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController)
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController)
UIPageViewControllerDelegate委託協議中通常實現的方法是:
func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation)
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
建立一個iOS工程
代碼實現UIPageViewController
// // ViewController.swift // PageNavigation // // Created by Michael on 2016/11/10. // Copyright © 2016年 Michael. All rights reserved. // import UIKit enum DirectionFroward : Int { case Before = 1 //向前 case After = 2 //向後 } class ViewController: UIViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource { //當前Page的索引 var mPageIndex = 0 var direct = DirectionFroward.After var mPageViewController : UIPageViewController! var mViewControllers : [UIViewController]! override func viewDidLoad() { super.viewDidLoad() let pageViewController1 = UIViewController() let pageViewController2 = UIViewController() let pageViewController3 = UIViewController() self.mViewControllers = [pageViewController1,pageViewController2,pageViewController3] let mImage1 = UIImageView(frame: self.view.frame) mImage1.image = UIImage(named: "達芬奇-蒙娜麗莎") pageViewController1.view.addSubview(mImage1) let mImage2 = UIImageView(frame: self.view.frame) mImage2.image = UIImage(named: "羅丹-思想者") pageViewController2.view.addSubview(mImage2) let mImage3 = UIImageView(frame: self.view.frame) mImage3.image = UIImage(named: "保羅克利-肖像") pageViewController3.view.addSubview(mImage3) //transitionStyle: pageCurl表示翻書效果樣式 scroll 滑屏效果樣式 //navigationOrientation 水平和垂直方向 self.mPageViewController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil) self.mPageViewController.delegate = self self.mPageViewController.dataSource = self //設置首頁 //direction forward向前 reverse向後 self.mPageViewController.setViewControllers([pageViewController1], direction: .forward, animated: true, completion: nil) self.view.addSubview(self.mPageViewController.view) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } //DataSource協議 func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { NSLog("向前翻") mPageIndex -= 1 if mPageIndex < 0 { mPageIndex = 0; return nil } direct = .Before return self.mViewControllers[mPageIndex] } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { NSLog("向後翻") mPageIndex += 1 if mPageIndex > 2 { mPageIndex = 2 return nil } direct = .After return self.mViewControllers[mPageIndex] } //Delegate協議 func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewControllerSpineLocation { self.mPageViewController.isDoubleSided = false //min和max 首頁顯示一個視圖 mid首頁顯示兩個視圖 return .min } func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { //翻頁未成功 if completed == false { if direct == .After { mPageIndex -= 1 } if direct == .Before { mPageIndex += 1 } } } }
使用標籤欄時有必定的指導原則:標籤欄位於屏幕下方,佔有49個像素屏幕空間,有時能夠隱藏起來;標籤欄中的標籤不能超過5個,若是超過5個則最後一個顯示爲更多,點擊更多標籤會出現更多的列表。
在開發具體應用的時候,標籤導航的各個標籤分別表明一個功能模塊,各功能模塊之間相對獨立。
建立一個iOS工程模板Tabbed Application應用,默認建立兩個標籤
從對象庫中拖入一個ViewController到故事板中
添加ViewController和Tab Controller Scene的連線,具體操做是:按住control鍵從Tab Controller Scene拖曳鼠標到ViewController,釋放鼠標,從彈出窗口中選擇view controllers項便可
設置三個場景的標題
分別爲三個場景建立三個視圖類
// // HeiViewController.swift // TabNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class HeiViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ }
// // JiViewController.swift // TabNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class JiViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ }
// // LiaoViewController.swift // TabNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class LiaoViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ }
樹形導航模式是將導航控制器UINavigationController與表視圖結使用,主要用於構建從屬關係的導航。下面咱們建立一個三級視圖的樹形導航示例。
建立iOS工程,使用UINavigationController建立以及表視圖
建立二級表視圖CitiesViewController
從對象庫中拖入一個Table View Controller到對象庫中做爲二級視圖控制器
按住control鍵,從上一個Root View Controller的單元格中拖動鼠標到當前添加的Table View Controller中,釋放鼠標,在彈出窗口中選擇Show選項
選擇鏈接線中的過渡Segue,打開其屬性檢查器,而後在Indentifier屬性中輸入ShowCities
建立三級視圖DetailViewController
從對象庫中拖入一個View Controller到對象庫中做爲三級視圖控制器
按住control鍵,從上一個Table View Controller的單元格中拖動鼠標到當前添加的View Controller中,釋放鼠標,在彈出窗口中選擇Show選項
選擇鏈接線中的過渡Segue,打開其屬性檢查器,而後在Indentifier屬性中輸入ShowDetail
設置各級視圖的Table View Cell的屬性
一級視圖
// // ViewController.swift // TreeNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class ViewController: UITableViewController { var dictData:NSDictionary! var listData:NSArray! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.tableView.delegate = self self.tableView.dataSource = self let path = Bundle.main.path(forResource: "provinces_cities", ofType: "plist") self.dictData = NSDictionary(contentsOfFile: path!) self.listData = self.dictData.allKeys as NSArray self.title = "省份信息" } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.listData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell:UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: "Custom", for: indexPath) let row = indexPath.row cell.textLabel?.text = self.listData[row] as? String return cell } //場景過渡以前的處理 點擊表視圖的單元格觸發 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ShowCities" { let indexPath = self.tableView.indexPathForSelectedRow! as IndexPath let selectedIndex = indexPath.row //獲取要跳轉到的視圖控制器對象 let controller = segue.destination as! CitiesTableViewController let selectName = self.listData[selectedIndex] as! String controller.listData = self.dictData[selectName] as! NSArray controller.title = selectName } } }
二級視圖
// // CitiesTableViewController.swift // TreeNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit class CitiesTableViewController: UITableViewController { var listData:NSArray! override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return self.listData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell:UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: "CityCell", for: indexPath) let row = indexPath.row let dict = self.listData[row] as! NSDictionary cell.textLabel?.text = dict["name"] as? String return cell } //場景過渡以前的與處理 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ShowDetail" { let indexPath = self.tableView.indexPathForSelectedRow! as IndexPath let selectIndex = indexPath.row let dict = self.listData[selectIndex] as! NSDictionary //獲取要跳轉到的視圖控制器對象 let controller = segue.destination as! DetailViewController controller.url = dict["url"] as! String controller.title = dict["name"] as? String } } }
三級視圖
// // DetailViewController.swift // TreeNavigation // // Created by Michael on 2016/11/15. // Copyright © 2016年 Michael. All rights reserved. // import UIKit import WebKit class DetailViewController: UIViewController,WKNavigationDelegate { var url:String! var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() NSLog(url) self.webView = WKWebView(frame: self.view.frame) view.addSubview(webView) webView.navigationDelegate = self //let nUrl = URL(string: "https://baike.baidu.com/view/2172.htm") let mUrl = URL(string: url) let request = URLRequest(url: mUrl!) webView.load(request) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { NSLog("開始加載") } func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { NSLog("內容開始返回時回調") } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { NSLog("加載完成") } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { NSLog("加載失敗") } }