@@ -59,7 +59,7 @@ public class MRNavigator {
5959 }
6060
6161 public func navigate( to route: MRRoute ,
62- from viewController: UIViewController ,
62+ from viewController: UIViewController ? = nil ,
6363 navigationType: NavigationType = . push,
6464 animated: Bool = true ,
6565 completion: ( ( ) -> Void ) ? = nil ) {
@@ -82,8 +82,8 @@ public class MRNavigator {
8282 return false
8383 }
8484
85- if let rootVC = UIApplication . shared . windows . first ( where : { $0 . isKeyWindow } ) ? . rootViewController {
86- navigate ( to: route, from: rootVC )
85+ if let topvc = topViewController ( ) {
86+ navigate ( to: route, from: topvc )
8787 return true
8888 }
8989 return false
@@ -121,7 +121,7 @@ public class MRNavigator {
121121 }
122122
123123 private func handleResult( _ result: RouteResult ,
124- from viewController: UIViewController ,
124+ from viewController: UIViewController ? ,
125125 navigationType: NavigationType ,
126126 animated: Bool ,
127127 completion: ( ( ) -> Void ) ? ) {
@@ -143,21 +143,31 @@ public class MRNavigator {
143143 }
144144
145145 private func perform( navigation type: NavigationType ,
146- from: UIViewController ,
146+ from: UIViewController ? ,
147147 to: UIViewController ,
148148 animated: Bool ,
149149 completion: ( ( ) -> Void ) ? ) {
150+ var temp = ( from != nil ) ? from : topViewController ( )
151+ guard let base = temp else {
152+ completion ? ( )
153+ return
154+ }
150155 switch type {
151156 case . push:
152- from. navigationController? . pushViewController ( to, animated: animated)
153- completion ? ( )
157+ if let navigationController = base. navigationController {
158+ navigationController. pushViewController ( to, animated: animated)
159+ completion ? ( )
160+ } else {
161+ let nav = UINavigationController ( rootViewController: to)
162+ base. present ( nav, animated: animated, completion: completion)
163+ }
154164 case . present:
155- from . present ( to, animated: animated, completion: completion)
165+ base . present ( to, animated: animated, completion: completion)
156166 case . modal:
157167 to. modalPresentationStyle = . fullScreen
158- from . present ( to, animated: animated, completion: completion)
168+ base . present ( to, animated: animated, completion: completion)
159169 case . replace:
160- guard let navigationController = from . navigationController else {
170+ guard let navigationController = base . navigationController else {
161171 completion ? ( )
162172 return
163173 }
@@ -167,7 +177,7 @@ public class MRNavigator {
167177 navigationController. setViewControllers ( viewControllers, animated: animated)
168178 completion ? ( )
169179 case . custom( let handler) :
170- handler ( from , to)
180+ handler ( base , to)
171181 completion ? ( )
172182 }
173183 }
@@ -185,3 +195,70 @@ public class MRNavigator {
185195 metadata: [ " params " : route. params, " result " : String ( describing: result) ] )
186196 }
187197}
198+
199+
200+ public extension MRNavigator {
201+
202+ /// Get the top most view controller from the base view controller; default param is UIWindow's rootViewController
203+ func topViewController( _ from: UIViewController ? = nil ) -> UIViewController ? {
204+ var base = ( from != nil ) ? from : compatibleKeyWindow? . rootViewController
205+ if let nav = base as? UINavigationController {
206+ return topViewController ( nav. visibleViewController)
207+ }
208+ if let tab = base as? UITabBarController {
209+ if let selected = tab. selectedViewController {
210+ return topViewController ( selected)
211+ }
212+ }
213+ if let presented = base? . presentedViewController {
214+ return topViewController ( presented)
215+ }
216+ return base
217+ }
218+
219+ var compatibleKeyWindow : UIWindow ? {
220+ if #available( iOS 13 , * ) {
221+ return UIApplication . shared. connectedScenes
222+ . compactMap { $0 as? UIWindowScene }
223+ . flatMap { $0. windows }
224+ . first { $0. isKeyWindow }
225+ } else {
226+ return UIApplication . shared. keyWindow
227+ }
228+ }
229+ /// 重置应用到根视图控制器
230+ func resetToRootViewController( _ animated: Bool = false ) {
231+ guard let window = compatibleKeyWindow,
232+ let rootViewController = window. rootViewController else {
233+ return
234+ }
235+
236+ // 1. 先处理当前显示的模态视图
237+ if let presentedVC = rootViewController. presentedViewController {
238+ presentedVC. dismiss ( animated: false ) {
239+ self . resetToRootHelper ( rootViewController, animated: animated)
240+ }
241+ } else {
242+ resetToRootHelper ( rootViewController, animated: animated)
243+ }
244+ }
245+
246+ private func resetToRootHelper( _ rootViewController: UIViewController , animated: Bool ) {
247+ // 2. 处理 UINavigationController
248+ if let navigationController = rootViewController as? UINavigationController {
249+ navigationController. popToRootViewController ( animated: animated)
250+ }
251+
252+ // 3. 处理 UITabBarController
253+ if let tabBarController = rootViewController as? UITabBarController {
254+ // 重置所有 tab 的导航栈
255+ tabBarController. viewControllers? . forEach { viewController in
256+ if let navigationController = viewController as? UINavigationController {
257+ navigationController. popToRootViewController ( animated: animated)
258+ }
259+ }
260+ // 切换到第一个 tab
261+ tabBarController. selectedIndex = 0
262+ }
263+ }
264+ }
0 commit comments