Swift页面跳转的几种方式
学会一周的UIKit了,还不会页面跳转。枯了~
今天搞通了swift页面跳转。如果对比前端或者说web应用,其实就是“路由”,像react应用,可以通过react-router来管理路由,vue可以通过vue-router来管理路由类似,swift中可以用UINavigationController
来管理“路由”,这里应该叫“导航”吧。iOS中有两种不同形式的跳转,一种是有逻辑层级关系的跳转,一种是临时页面的跳转。
临时的页面跳转
我觉得可以看作是一个弹出页,比如点击一个表单控件,可以弹出一个相应的编辑页。这个是属于该页面的行为,所以不需要全局使用,视图自带。
跳转到下一页,可以用self.present(anotherView, animated: true, completion: nil)
,这样页面会从底部弹出。收回页面,调用self.dismiss(animated: true, completion: nil)
。这里灰常简单,就认识俩方法而已。
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
initBtn()
}
//初始化按钮,点击按钮跳转页面
func initBtn() {
let screenSize = UIScreen.main.bounds.size
let jumpBtn = UIButton(type: .system)
jumpBtn.setTitle("跳转", for: .normal)
jumpBtn.frame = CGRect(x: screenSize.width / 2 - 50, y: screenSize.height - 50, width: 100, height: 30)
jumpBtn.backgroundColor = .blue
jumpBtn.setTitleColor(UIColor.white, for: .normal)
//按钮绑定事件,点击时执行
jumpBtn.addTarget(self, action: #selector(pageJump), for: .touchDown)
self.view.addSubview(jumpBtn)
}
@objc func pageJump() {
print("main to dest")
//创建一个页面
let destination = DestinationViewController()
//取目标页面的一个变量进行赋值,以属性的方式进行传值。
destination.message = "传递的信息"
//跳转
self.present(destination, animated: true, completion: nil)
}
}
ViewController.swift
DestinationViewContrller.swift
import UIKit
class DestinationViewController: UIViewController {
var message: String?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
initBtn()
print(message!)
}
//初始化返回按钮,点击按钮返回主页面。
func initBtn() {
let screenSize = UIScreen.main.bounds.size
let jumpBtn = UIButton(type: .system)
jumpBtn.setTitle("返回", for: .normal)
jumpBtn.frame = CGRect(x: screenSize.width / 2 - 50, y: screenSize.height - 100, width: 100, height: 30)
jumpBtn.backgroundColor = .red
jumpBtn.setTitleColor(UIColor.white, for: .normal)
//按钮绑定事件
jumpBtn.addTarget(self, action: #selector(pageReturn), for: .touchDown)
self.view.addSubview(jumpBtn)
}
@objc func pageReturn() {
print("dest to main")
//返回主页面
self.dismiss(animated: true, completion: nil)
}
}
DestinationViewController.swift
具有逻辑层次的页面跳转
比如网上购物,下单之后要跳到订单页面,再跳到支付页面等等,这种跳转是有一定逻辑,或者说先后顺序的。这种跳转需要用NavigationViewController
进行跳转。
还是上面那个例子:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
initBtn()
}
//初始化按钮,点击按钮跳转页面
func initBtn() {
let screenSize = UIScreen.main.bounds.size
let jumpBtn = UIButton(type: .system)
jumpBtn.setTitle("跳转", for: .normal)
jumpBtn.frame = CGRect(x: screenSize.width / 2 - 50, y: screenSize.height - 50, width: 100, height: 30)
jumpBtn.backgroundColor = .blue
jumpBtn.setTitleColor(UIColor.white, for: .normal)
//按钮绑定事件,点击时执行
jumpBtn.addTarget(self, action: #selector(pageJump), for: .touchDown)
self.view.addSubview(jumpBtn)
}
@objc func pageJump() {
print("main to dest")
//创建一个页面
let destination = DestinationViewController()
//取目标页面的一个变量进行赋值,以属性的方式进行传值。
destination.message = "传递的信息"
//跳转
self.navigationController?.pushViewController(destination, animated: true)
}
}
ViewController.swift
DestinationViewController.swift
import UIKit
class DestinationViewController: UIViewController {
var message: String?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
initBtn()
print(message!)
}
//初始化返回按钮,点击按钮返回主页面。
func initBtn() {
let screenSize = UIScreen.main.bounds.size
let jumpBtn = UIButton(type: .system)
jumpBtn.setTitle("返回", for: .normal)
jumpBtn.frame = CGRect(x: screenSize.width / 2 - 50, y: screenSize.height - 50, width: 100, height: 30)
jumpBtn.backgroundColor = .red
jumpBtn.setTitleColor(UIColor.white, for: .normal)
//按钮绑定事件
jumpBtn.addTarget(self, action: #selector(pageReturn), for: .touchDown)
self.view.addSubview(jumpBtn)
}
@objc func pageReturn() {
print("dest to main")
//返回主页面
self.navigationController?.popViewController(animated: true)
}
}
DestinationViewController.swift
但是如果这时编译页面,在模拟器中点击Next按钮,发现并没有任何事情发生😅这块找了半天才找到解决办法,最后发现,是没有实例化UINavigationController
,其实看到navigationController
是一个可选类型就可以猜到一二。
接下来,该在什么地方实例化这个UINavigationController
呢?如果你直接在页面实例化,发现一样不管用。类比一下react里的路由(react-router 4.0之前的版本),就会发现,导航其实是一个全局的东西,来管理所有的界面堆栈,而不是存在于某一个页面内。如果放入某一个页面内,每次加载都是实例化的一个新UINavigationController
,它在其他页面是没法被拿到的。如这个例子中,如果在第一页实例化一个导航控制器,在第二页中是拿不到的。所以,要解决这个问题,就要实例化一个全局的UINavigationController
。
我们可以在AppDelegate.swift
中实例化这个全局导航器。如果有SceneDelegate.swift
中实例化。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
let vc = ViewController()
let navRoot = UINavigationController(rootViewController: vc)
self.window?.rootViewController = navRoot
self.window?.backgroundColor = UIColor.white
}
...
...
}
即通过给window的rootViewController赋值一个UINavigationController
实例,就可以在所有页面使用navigationController
了。这里其实是重写了应用启动后的默认行为,所以需要在实例化UINavigationController
时指定一下根试图。然后给个背景色,否则是黑的😓。这样就可以了,其他页面直接使用pushViewController
和popViewController
就可以了。
还有两个有用的跳转方法
// 第三个按钮绑定的方法,根据全局序号,查找堆栈中指定序号的视图控制器
@objc func gotoIndexPage(){
let viewController = self.navigationController?.viewControllers[1]
self.navigationController?.popToViewController(viewController!, animated: true)
}
// 创建第四个按钮绑定的方法,所有子视图出栈
@objc func gotoRootPage(){
self.navigationController?.popToRootViewController(animated: true)
}
3. segue
使用segue进行跳转第一步必须在storyboard中创建segue,暂不讨论。
参考链接:
1. https://www.dazhuanlan.com/2019/12/25/5e024f564f7e3/
2. https://github.com/Wellcomezhangheng/swift-componentization/tree/master/Runtime_Componentized
3. https://blog.csdn.net/weixin_41735943/article/details/81142709
原编辑时间 2020-12-01 14:47