在app中页面跳转是无法回避的问题, 我们平常在代码中遇到跳转基本都是
let vc = UIViewController() self.navigationController?.pushViewController(vc, animated: true)
后面出现了storyboard后可以通过连线进行跳转,传参通过
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
获取到要跳转的对象进行传参, 后来还有了Reference可以跳到不同的storyboard,不得不说这样真的方便,但个人感觉这样同时也有一个缺点就是不明确, 我在追踪的时候不容易跟踪, 自己写的过段时间忘了或者说后来人看你写的代码很难理解
所以写了个简单的路由器, 现在网上也有类似的实现 比如 HHRouter routable-ios 等
现有项目要用Swift, 所以做了个Swift版本的跳转 有以下基本需求
1: 做到write once run anywhere,
2: 页面初始化支持code, xib, storyboard, 传参,
3: 基本页面跳转(push, present), 内部外部网页跳转,推送通知跳转
4: 松耦合
考虑到以上,写了个基本的Routable协议,如果这个ViewController要想支持跳转就必须实现这个协议
协议中的两个方法
一个是初始化, 一个是返回这个ViewController对应的key
public protocol Routable { /** 类的初始化方法 - params 传参字典 */ static func initWithParams(params: RouterParam?) -> UIViewController /** 每个类跳转对应的key */ static var routableKey:String { get } }
同时在设置了根控制器之后,将此ViewController的key与类名进行对应起来
let router = Router.sharedInstance router.navigationController = nav router.map(FirstViewController.routableKey, className: FirstViewController.description()) router.map(SecondViewController.routableKey, className: SecondViewController.description()) router.map(WebViewController.routableKey, className: WebViewController.description()) router.map(FirstNavigationController.routableKey, className: FirstNavigationController.description())
传参,由于Swift是强类型的,没办法字典中用了Any做为Value
public typealias RouterParam = [String: Any]
同时为了支持present时的动画效果,添加了RouterOptions来支持一些额外的效果或者要求
public class RouterOptions { let presentationStyle: UIModalPresentationStyle let transitionStyle: UIModalTransitionStyle /** 只有在isModal为true是才会考虑modal下的style */ var isModal = false /** 只对pushViewController有效 */ var shouldOpenAsRoot = false public class func rootOptions() -> RouterOptions { return RouterOptions(presentationStyle: .FullScreen, transitionStyle: .CoverVertical, isModal: false, isRoot: true) } public class func modalOptions() -> RouterOptions { return RouterOptions(presentationStyle: .FullScreen, transitionStyle: .CoverVertical, isModal: true, isRoot: false) } public init(presentationStyle: UIModalPresentationStyle, transitionStyle: UIModalTransitionStyle, isModal: Bool) { self.presentationStyle = presentationStyle self.transitionStyle = transitionStyle self.isModal = isModal } public init(presentationStyle: UIModalPresentationStyle, transitionStyle: UIModalTransitionStyle, isRoot: Bool) { self.presentationStyle = presentationStyle self.transitionStyle = transitionStyle self.shouldOpenAsRoot = isRoot } private init(presentationStyle: UIModalPresentationStyle, transitionStyle: UIModalTransitionStyle, isModal: Bool, isRoot: Bool) { self.presentationStyle = presentationStyle self.transitionStyle = transitionStyle self.isModal = isModal self.shouldOpenAsRoot = isRoot } }
调用open进入新界面,可以选择性的是否传入参数,动画效果, present时的options要求, push/present后的回调等
private func open(key: String, params: RouterParam?, options: RouterOptions?, animated: Bool, completion: ((opened: UIViewController?) -> Void)?) { }
添加了基本的打电话,打开外部网页功能,打开外部app
同时写了基本的使用demo 详细代码见 Router
待优化的地方
1: 传参是否可优化?
2: 更多场景测试
3: 频繁open时是否需要容错,
4: 是否需要抛出Exception
你有什么好的建议也可留言