-
-
Save snikch/3661188 to your computer and use it in GitHub Desktop.
- (UIViewController *)topViewController{ | |
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; | |
} | |
- (UIViewController *)topViewController:(UIViewController *)rootViewController | |
{ | |
if (rootViewController.presentedViewController == nil) { | |
return rootViewController; | |
} | |
if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) { | |
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController; | |
UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; | |
return [self topViewController:lastViewController]; | |
} | |
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController; | |
return [self topViewController:presentedViewController]; | |
} |
Same of yonat but in Obj-C ;)
- (UIViewController *)topViewController{
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController;
return [self topViewController:[navigationController.viewControllers lastObject]];
}
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabController = (UITabBarController *)rootViewController;
return [self topViewController:tabController.selectedViewController];
}
if (rootViewController.presentedViewController) {
return [self topViewController:rootViewController];
}
return rootViewController;
}
Awesome :)
nice one.
Transcribed to Rubymotion
def topViewController
topViewController(UIApplication.sharedApplication.keyWindow.rootViewController)
end
def topViewController(rootViewController)
return rootViewController unless rootViewController.presentedViewController
if rootViewController.presentedViewController.is_a?(UINavigationController)
return rootViewController.presentedViewController.viewControllers.last
end
return topViewController(rootViewController.presentedViewController)
end
I am so curious about the differences between this and the property visibleViewController of UINavigationViewController. Thanks~
@PoissonBallon I think it should be
if (rootViewController.presentedViewController) {
// instead of just [self topViewController:rootViewController];
return [self topViewController:rootViewController.presentedViewController)];
}
Awesome solution, nice use of recursivity ;)
good, but how to find the current view‘s navigation controller, for example , uitableviewcell has uiimageview for photo, but it can be tapped to push another viewcontroller, like twitter tap photo, how to solve that
A slightly more Swifty version of the variations above.
`
extension UIViewController {
class func topMostViewController() -> UIViewController? {
return UIViewController.topViewControllerForRoot(UIApplication.sharedApplication().keyWindow?.rootViewController)
}
class func topViewControllerForRoot(rootViewController:UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
guard let presented = rootViewController.presentedViewController else {
return rootViewController
}
switch presented {
case is UINavigationController:
let navigationController:UINavigationController = presented as! UINavigationController
return UIViewController.topViewControllerForRoot(navigationController.viewControllers.last)
case is UITabBarController:
let tabBarController:UITabBarController = presented as! UITabBarController
return UIViewController.topViewControllerForRoot(tabBarController.selectedViewController)
default:
return UIViewController.topViewControllerForRoot(presented)
}
}
}
`
very nice
my swift version :
extension AppDelegate {
func findCurrentViewController() -> UIViewController{
let rootVC = UIApplication.sharedApplication().keyWindow?.rootViewController
return findCurrentViewController(byTempTopVC: rootVC!)
}
func findCurrentViewController(byTempTopVC vc: UIViewController) -> UIViewController {
let presentedVC = vc.presentedViewController
guard presentedVC != nil else {
return vc
}
if presentedVC!.isKindOfClass(UINavigationController) {
let theNav = presentedVC
let theTopVC = theNav!.childViewControllers.last
return findCurrentViewController(byTempTopVC: theTopVC!)
}
return findCurrentViewController(byTempTopVC: presentedVC!)
}
}
I cleaned up @fvernon's swiftier version to be a bit more swifty:
extension UIViewController {
class func topViewController(rootViewController rootViewController: UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
guard let presented = rootViewController.presentedViewController else {
return rootViewController
}
switch presented {
case let navigationController as UINavigationController:
return topViewController(rootViewController: navigationController.viewControllers.last)
case let tabBarController as UITabBarController:
return topViewController(rootViewController: tabBarController.selectedViewController)
default:
return topViewController(rootViewController: presented)
}
}
}
I cleaned up @nuudles's version to be more swifty:
This version use iterator instead of recursive
extension UIApplication{
var topViewController: UIViewController?{
if keyWindow?.rootViewController == nil{
return keyWindow?.rootViewController
}
var pointedViewController = keyWindow?.rootViewController
while pointedViewController?.presentedViewController != nil {
switch pointedViewController?.presentedViewController {
case let navagationController as UINavigationController:
pointedViewController = navagationController.viewControllers.last
case let tabBarController as UITabBarController:
pointedViewController = tabBarController.selectedViewController
default:
pointedViewController = pointedViewController?.presentedViewController
}
}
return pointedViewController
}
}
and the usage example:
func applicationDidBecomeActive(_ application: UIApplication) {
debugPrint(application.topViewController)
}
Nice and useful code snippet.
Tested and working @nuudles post, repeating for confirmation:
func topViewController(rootViewController rootViewController: UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
guard let presented = rootViewController.presentedViewController else {
return rootViewController
}
switch presented {
case let navigationController as UINavigationController:
return topViewController(rootViewController: navigationController.viewControllers.last)
case let tabBarController as UITabBarController:
return topViewController(rootViewController: tabBarController.selectedViewController)
default:
return topViewController(rootViewController: presented)
}
}
What if rootViewController is a kind of UINavigationController and has no presentedViewController
@yonat
I tried using your code but the view i tried to load a blank page and then after like 1 min only the buttons in the view load , could you help me understand this? As to why this happens? Because I encounter the same problem when I tried testing the finger print sensor functions provided by Apple.
Thank you.
@wubingwell : i had the same problem, solved like this
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
switch(vc){
case is UINavigationController:
let navigationController = vc as! UINavigationController
return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!)
break;
case is UITabBarController:
let tabBarController = vc as! UITabBarController
return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!)
break;
default:
if let presentedViewController = vc.presentedViewController {
//print(presentedViewController)
if let presentedViewController2 = presentedViewController.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController2)
}
else{
return vc;
}
}
else{
return vc;
}
break;
}
}
}
Usage :
if let topController = window?.visibleViewController() {
switch(topController){
case is MyCollectionViewController:
print("OK CollectionViewController")
break;
case is MyViewController:
print("OK ViewController")
break;
default:
print("OK but default")
break;
}
}
My ver to find topViewController with SSASideMenu
public extension UIApplication {
public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let SSASide = base as? SSASideMenu {
if let nav = SSASide.contentViewController as? UINavigationController{
return topViewController(nav.visibleViewController)
}
}
if let nav = base as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController, top.view.window != nil {
return topViewController(top)
} else if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(presented)
}
return base
}
I like mohammadshalhoob's version because it takes moreNavigationController into account. However, I found that moreNavigationController.topViewController.view.window != nil didn't work as intended when used in viewWillAppear, before the view is attached to the window. To test whether the sixth or more view controller is selected, I just used tab.selectedIndex > 4.
I'm curious where UIViewController's children has gone?
👍