Swift-Router 自己写个路由吧,第三方总是太复杂
Swift-Router 自己写个路由吧,第三方总是太复杂
先看看这个路由的使用吧
- 如果是网络地址,会直接自动跳转到 OtherWKWebViewController
- 如果是应用内部的手动调用跳转
- 直接跳转视图控制器
- EPRouter.pushViewController(EPSMSLoginViewController())
- 先在 RouteDict 注册映射关系再跳转
- EPRouter.pushAppURLPath("goods/detail?spellId=xxx&productId=xxx")
- 又服务器来控制跳转 也得在 RouteDict 注册映射关系,只不过多加了一个 scheme
- EPRouter.pushURLPath("applicationScheme://goods/detail?spellId=xxx&productId=xxx")
**!!!支持Swift、OC、Storyboard的跳转方式,可以在 loadViewController 看到实现方式 **
EPRouter的全部代码
class EPRouter: NSObject {
private static let RouteDict:[String:String] = [
"order/list" :"OrderListPageViewController", // 订单列表 segmentIndex
"order/detail" :"OrderDetailViewController", // 订单详情 orderId
"goods/detail" :"GoodsDetailViewController", // 商品详情productId
"goods/list" :"GoodsCategoryViewController", // type brandId 跳转到某个分类;跳转到某个品牌
"goods/search" :"SearchListViewController", // 搜索商品 text
"coupon/list" :"CouponListViewController", // 优惠券列表
"cart/list" :"CartViewController", // 购物车列表
"address/list" :"AddressListViewController", // 收货地址列表
]
// 返回首页,然后指定选中模块
public static func backToTabBarController(index: NSInteger, completion:(()->())?=nil) {
guard let vc = EPCtrlManager.getTopVC(), let nav = vc.navigationController, let tabBarCtrl = nav.tabBarController else {
return
}
nav.popToRootViewController(animated: false)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.1) {
tabBarCtrl.selectedIndex = index
completion?()
}
}
// 销毁n个界面 不建议使用这个方法 可以在pushAppURLPath方法中设置destroyTime达到一样的效果,又可以避免用户侧滑返回
public static func popViewController(animated: Bool, time:NSInteger=1) {
guard let nav = EPCtrlManager.getTopVC()?.navigationController else {
return
}
let vcs = nav.viewControllers
let count = vcs.count
let index = (count - 1) - time
if index >= 0 {
let vc = vcs[index]
nav.popToViewController(vc, animated: true)
} else {
nav.popViewController(animated: true)
}
}
/// 回到目标控制器
public static func popViewController(targetVC: UIViewController.Type, animated: Bool, toRootVC: Bool=true) {
popViewController(targetVCs: [targetVC], animated: animated, toRootVC: toRootVC)
}
/// 回到目标控制器[vc],从前到后 没有目标控制器是否回到根视图
public static func popViewController(targetVCs: [UIViewController.Type], animated: Bool, toRootVC: Bool=true) {
guard let nav = EPCtrlManager.getTopVC()?.navigationController else {
return
}
let vcs = nav.viewControllers
var canPop = false
for vc in vcs {
for tvc in targetVCs {
if vc.isMember(of: tvc) {
canPop = true
nav.popToViewController(vc, animated: animated)
break
}
}
}
if !canPop && toRootVC {
nav.popToRootViewController(animated: animated)
}
}
/// push 一个vc --- destroyTime: push之前要销毁的几个压栈vc
@objc public static func pushAppURLPath(_ path: String, query: [AnyHashable: Any]=[:], animated: Bool=true, destroyTime:NSInteger=0) {
var urlString = "applicationScheme://"+path
if path.contains("http://") || path.contains("https://") {
urlString = path
}
pushURLString(urlString, query: query, animated: animated, destroyTime: destroyTime)
}
@objc public static func pushURLString(_ urlString: String, query: [AnyHashable: Any]=[:], animated: Bool=true, destroyTime:NSInteger=0) {
guard let tvc = loadViewControllerWitURI(urlString, query: query) else {
return
}
pushViewController(tvc, animated: animated, destroyTime: destroyTime)
}
@objc public static func pushViewController(_ tvc: UIViewController, query: [AnyHashable: Any]=[:], animated: Bool=true, destroyTime:NSInteger=0) {
guard let vc = EPCtrlManager.getTopVC() else {
return
}
if let _ = tvc.pushInfo {
tvc.pushInfo?.merge(query, uniquingKeysWith: { (_, new) in new })
}else {
tvc.pushInfo = query
}
guard let nav = vc.navigationController else {
vc.present(tvc, animated: true, completion: nil)
return
}
tvc.hidesBottomBarWhenPushed = true
if destroyTime > 0 {
let vcs = nav.viewControllers
let count = vcs.count
var index = (count - 1) - destroyTime
if index < 0 { // destroyTime 很多时,直接从根视图push
index = 0
}
var reVCS = [UIViewController]()
for vc in nav.viewControllers[0...index] {
reVCS.append(vc)
}
reVCS.append(tvc)
nav.setViewControllers(reVCS, animated: animated)
}else {
nav.pushViewController(tvc, animated: animated)
}
}
public static func loadViewController(_ className: String, parameters: [AnyHashable: Any]? = nil) -> UIViewController? {
var desVC: UIViewController?
let spaceName = (Bundle.main.infoDictionary?["CFBundleExecutable"] as? String) ?? "ApplicationName"
if let vc = storyboardClass(className) { // storyboard
desVC = vc
}else if let aClass = NSClassFromString("\(spaceName).\(className)") { // Swift
if aClass is UIViewController.Type {
let type = aClass as! UIViewController.Type
desVC = type.init()
}
}else if let aClass = NSClassFromString("\(className)") { // OC
if aClass is UIViewController.Type {
let type = aClass as! UIViewController.Type
desVC = type.init()
}
}
desVC?.pushInfo = parameters
return desVC
}
public static func loadViewController(_ viewController: UIViewController, parameters: [AnyHashable: Any]? = nil) -> UIViewController {
viewController.pushInfo = parameters
return viewController
}
public static func loadViewControllerWitURI(_ urlString: String, query: [AnyHashable: Any]? = nil) -> UIViewController? {
// 先进行编码,防止有中文的带入, 不行进行二次编码
var urlString = urlString
if (URLComponents(string: urlString) == nil) {
urlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? urlString
}
guard let url = URLComponents(string: urlString), let scheme = url.scheme else {
HGLog("无效的地址:\(urlString)")
return nil
}
if scheme == "http" || scheme == "https" {
let webVC = OtherWKWebViewController()
webVC._urlStr = urlString
return webVC
} else if String(format: "%@://", scheme) == "appcationScheme://" {
let path = (url.host ?? "") + url.path
guard var vcClassName = RouteDict[path] else {
HGLog("没有配置视图控制器呢。。。:\(urlString)")
return nil
}
var info: [AnyHashable: Any]?
if query?.count ?? 0 > 0 {
info = [AnyHashable: Any]()
for (key, value) in query! {
info![key] = value
}
}
if let queryItems = url.queryItems {
if info == nil {
info = [AnyHashable: Any]()
}
for item in queryItems {
if let value = item.value {
info![item.name] = value
}
}
}
return loadViewController(vcClassName, parameters: info)
}
HGLog("未知scheme:\(urlString)")
return nil
}
private static func storyboardClass(_ className: String) -> UIViewController? {
if className == "VIPWithdrawViewController" { // 提现
let vc = UIStoryboard.init(name: "VIP", bundle: nil).instantiateViewController(withIdentifier: "withdrawTVC")
return vc
}else if className == "VIPRecordListViewController" { // 提现记录
let vc = UIStoryboard.init(name: "VIP", bundle: nil).instantiateViewController(withIdentifier: "recordListVC")
return vc
}
return nil
}
}
用来跳转传递数据的扩展属性
extension UIViewController {
private struct PushAssociatedKeys {
static var pushInfo = "pushInfo"
}
@objc open var pushInfo: [AnyHashable: Any]? {
get {
return objc_getAssociatedObject(self, &PushAssociatedKeys.pushInfo) as? [AnyHashable : Any]
}
set(newValue) {
objc_setAssociatedObject(self, &PushAssociatedKeys.pushInfo, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
可见视图控制器的获取
class EPCtrlManager: NSObject {
public static let `default`: EPCtrlManager = {
return EPCtrlManager()
}()
// MARK: **- 查找顶层控制器、**
// 获取顶层控制器 根据window
@objc public static func getTopVC() -> UIViewController? {
var window = UIApplication.shared.keyWindow
//是否为当前显示的window
if window?.windowLevel != UIWindow.Level.normal{
let windows = UIApplication.shared.windows
for windowTemp in windows{
if windowTemp.windowLevel == UIWindow.Level.normal{
window = windowTemp
break
}
}
}
let vc = window?.rootViewController
return getTopVC(withCurrentVC: vc)
}
///根据控制器获取 顶层控制器
private static func getTopVC(withCurrentVC VC :UIViewController?) -> UIViewController? {
if VC == nil {
print("🌶: 找不到顶层控制器")
return nil
}
if let presentVC = VC?.presentedViewController {
//modal出来的 控制器
return getTopVC(withCurrentVC: presentVC)
}else if let tabVC = VC as? UITabBarController {
// tabBar 的跟控制器
if let selectVC = tabVC.selectedViewController {
return getTopVC(withCurrentVC: selectVC)
}
return nil
} else if let naiVC = VC as? UINavigationController {
// 控制器是 nav
return getTopVC(withCurrentVC:naiVC.visibleViewController)
} else {
// 返回顶控制器
return VC
}
}
}