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 } } }
作者:TralyFang
链接:https://juejin.cn/post/7002427993792446501