摘要:负责控制器模态视图的控制器称为模态视图控制器,它并不是一个专门的类,它可以是前面提到的控制器的子类。负责主要任务视图的控制器称为主视图控制器。
模态视图
在导航过程中,有时候需要放弃主要任务而做其他次要任务,然后在返回到次要任务,这个次要任务就是在模态视图中完成的,如注册中主要任务是登录后进入主界面,如果用户没有注册,就要先去注册,注册是次要任务,当用户注册完成后,它会关闭注册视图,回到登录界面继续进行主要任务。
默认情况下,模态视图是从屏幕下方滑出来的。
负责控制器模态视图的控制器称为模态视图控制器,它并不是一个专门的类,它可以是前面提到的控制器的子类。负责主要任务视图的控制器称为主视图控制器。在UICOntrollerView中,主要有如下两个方法:
-present():呈现视图
-dismiss():关闭视图
在呈现模态视图时有两种方式:一是通过使用UIViewController的present方法实现;二是通过故事板的“过渡”(Segue)实现。
下面我们通过登录案例来介绍模态视图
步骤创建一个iOS工程,将当前控制器嵌入到一个导航控制器中,具体步骤是:在故事板中选择View Controller,然后点击Xcode菜单栏Editor-Embed In-Navigation Controller菜单就会自动创建一个导航视图
点击导航栏,将导航栏的标题设为登录,然后从对象库中拖入Lable、TextField、Button等控件
接下来设计第二个界面,先从对象库中拖入一个View Controller到设计界面中,然后参考步骤1将该视图控制器嵌入到导航控制器中,修改该导航栏标题为注册,然后从对象库中拖入两个Bar Button Item到导航栏两边,分别设置identifier属性为Cancel和Save
接下来需要在登录场景和注册场景创建一个过渡,按住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("加载失败") } }效果图
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/16524.html
摘要:界面应用界面主要是使用框架开发,它有一套自己的模式,其中视图和控制器是中的及其子类和及其子类。应用界面构建层次一般情况下,用于中只包含一个。 iOS界面应用界面主要是使用Cocoa Touch框架开发,它有一套自己的MVC模式,其中视图和控制器是UIKit中的UIVIew及其子类和UIVIewController及其子类。 视图控制器 Cocoa Touch中UIVIewControl...
摘要:展示器包含视图逻辑用于准备显示内容从交互器接收的并反馈用户输入通过显示器请求最新数据。交互器所做的工作应该是独立于任何用户界面的。同样的交互器可以在应用或应用中使用。 【编者按】本篇文章由 Jeff Gilbert 和 Conrad Stoll 共同编写,通过构建一个基础示例应用,深入了解 VIPER,并从视图、交互器等多个部件理清 VIPER 的整体布局及思路。通过 VIPER 构建...
摘要:而在中,我们可以将看做是,但它与并不是完全等价的。中包含有状态和无状态,分别用和表示。在中,由于是不可变的,没有与等价的功能函数。在中,要是先透明需要使用透明的包装一下才能实现。近似于中的,的工作机制和中的一致。文章概述 本人之前主要从事iOS开发工作,刚好Flutter文档中有一篇Flutter for iOS developers的文档,之前两篇文章,我们大致上体验了Flutter,这篇...
摘要:而在中,我们可以将看做是,但它与并不是完全等价的。中包含有状态和无状态,分别用和表示。在中,由于是不可变的,没有与等价的功能函数。在中,要是先透明需要使用透明的包装一下才能实现。近似于中的,的工作机制和中的一致。文章概述 本人之前主要从事iOS开发工作,刚好Flutter文档中有一篇Flutter for iOS developers的文档,之前两篇文章,我们大致上体验了Flutter,这篇...
摘要:背景目前,开源社区和业界内已经存在一些导航栏转场的解决方案,但对于历史包袱沉重的美团而言,这些解决方案并不完美。中的导航栏属于各个业务方的公用资源,由于缺乏相应的约束机制和最佳实践,导致业务方之间的代码耦合程度不断增加。 背景 目前,开源社区和业界内已经存在一些 iOS 导航栏转场的解决方案,但对于历史包袱沉重的美团 App 而言,这些解决方案并不完美。有的方案不能满足复杂的页面跳转场...
阅读 3239·2021-11-25 09:43
阅读 1514·2021-11-16 11:44
阅读 4570·2021-11-12 10:35
阅读 2798·2021-10-08 10:04
阅读 2331·2021-09-22 15:54
阅读 385·2019-08-30 15:55
阅读 767·2019-08-30 15:55
阅读 1806·2019-08-30 15:55