本文讲的是用 RxSwift 实现通用的响应式转场,
个人而言,我喜欢 UIStoryboardSegue 这个类背后的思路,把导航逻辑从业务逻辑程序中分离出来。
但是我并不推崇通过 storyboard 来实现这个方法,并且我也从来没有在代码中实现过。
所以我决定吸取上文的思想,自己做一个类似的东西。
但是这个类型应该有哪些域呢?
当然必须要有
let fromViewController:UIViewController
很多人会把想要显示的 context 传递给下一个 ViewController。
因为 Swift 有一个很酷的功能叫泛型,我们可以利用它把 context 变成通用类型 T
同时,我们还需要创建 toViewController 对象,我决定用 block 来做
let toViewControllerFactory:(context:T) -> UIViewController
现在我们可以实现转场的“响应式”部分了 =)
转场可以做两件事—— push 新的 viewController ,或者以模式方式显示。
private(set) lazy var pushObserver:AnyObserver
private(set) lazy var presentObserver:AnyObserver
我们来实现这些 observers
import UIKit
import RxSwift
class Segue {
private(set) weak var fromViewController:UIViewController?
let toViewControllerFactory:(context:T) -> UIViewController
init(fromViewController:UIViewController,
toViewControllerFactory:(context:T) -> UIViewController) {
self.fromViewController = fromViewController
self.toViewControllerFactory = toViewControllerFactory
}
private(set) lazy var pushObserver:AnyObserver = AnyObserver {[weak self] event in
switch event {
case .Next(let value):
guard let strong = self else {return}
let toViewController = strong.toViewControllerFactory(context: value)
strong.fromViewController?.navigationController?
.pushViewController(toViewController, animated:true)
default:
break
}
}
private(set) lazy var presentObserver:AnyObserver = AnyObserver {[weak self] event in
switch event {
case .Next(let value):
guard let strong = self else {return}
let toViewController = strong.toViewControllerFactory(context: value)
strong.fromViewController?.presentViewController(toViewController, animated: true, completion: nil)
default:
break
}
}
}
注意:如果你不想在转场中传递 context ,需要把它创建成 Void 类型
lazy var segue:Segue
现在我们可以这样使用转场了:
import RxSwift
import RxCocoa
class SomeTableViewController:UITableViewController {
let disposeBag = DisposeBag()
let items:[Item] ...
lazy var itemDetailsSegue:Segue = {
return Segue(fromViewController: self,
toViewControllerFactory: { context -> UIViewController in
return ItemDetailsViewController(item:context)
})
}
lazy var voidModalSegue:Segue = {
return Segue(fromViewController: self,
toViewControllerFactory: { _ -> UIViewController in
return SomeViewController()
})
}
override func viewDidLoad() {
super.viewDidLoad()
someButton.rx_tap
.bindTo(voidModalSegue.presentObserver)
.addDisposableTo(disposeBag)
tableView.rx_itemSelected
.map({[unowned self] indexPath in self.items.[indexPath.row]})
.bindTo(itemDetailsSegue.pushObserver)
.addDisposableTo(disposeBag)
}
}
结果如何?导航逻辑被分离出来了,而且这个类很容易进行单元测试。
大家有什么想法评论,欢迎留言讨论 :)
原文发布时间为:2016年09月10日
本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。
时间: 2024-10-27 06:26:49