Getting reference to the top-most view/window in iOS application

Objective CUiviewIosUiwindow

Objective C Problem Overview


I'm creating a reusable framework for displaying notifications in an iOS application. I'd like the notification views to be added over the top of everything else in the application, sort of like a UIAlertView. When I init the manager that listens for NSNotification events and adds views in response, I need to get a reference to the top-most view in the application. This is what I have at the moment:

_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

Would this work for any iOS application or is their a safer/better way to get the top view?

Objective C Solutions


Solution 1 - Objective C

Whenever I want to display some overlay on top of everything else, I just add it on top of the Application Window directly:

[[[UIApplication sharedApplication] keyWindow] addSubview:someView]

Solution 2 - Objective C

There are two parts of the problem: Top window, top view on top window.

All the existing answers missed the top window part. But [[UIApplication sharedApplication] keyWindow] is not guaranteed to be the top window.

  1. Top window. It is very unlikely that there will be two windows with the same windowLevel coexist for an app, so we can sort all the windows by windowLevel and get the topmost one.

     UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
     	return win1.windowLevel - win2.windowLevel;
     }] lastObject];
    
  2. Top view on top window. Just to be complete. As already pointed out in the question:

     UIView *topView = [[topWindow subviews] lastObject];
    

Solution 3 - Objective C

Usually that will give you the top view, but there's no guarantee that it's visible to the user. It could be off the screen, have an alpha of 0.0, or could be have size of 0x0 for example.

It could also be that the keyWindow has no subviews, so you should probably test for that first. This would be unusual, but it's not impossible.

UIWindow is a subclass of UIView, so if you want to make sure your notification is visible to the user, you can add it directly to the keyWindow using addSubview: and it will instantly be the top most view. I'm not sure if this is what you're looking to do though. (Based on your question, it looks like you already know this.)

Solution 4 - Objective C

Actually there could be more than one UIWindow in your application. For example, if a keyboard is on screen then [[UIApplication sharedApplication] windows] will contain at least two windows (your key-window and the keyboard window).

So if you want your view to appear ontop of both of them then you gotta do something like:

[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];

(Assuming lastObject contains the window with the highest windowLevel priority).

Solution 5 - Objective C

I'm sticking to the question as the title states and not the discussion. Which view is top visible on any given point?

@implementation UIView (Extra)

- (UIView *)findTopMostViewForPoint:(CGPoint)point
{
    for(int i = self.subviews.count - 1; i >= 0; i--)
    {
        UIView *subview = [self.subviews objectAtIndex:i];
        if(!subview.hidden && CGRectContainsPoint(subview.frame, point))
        {
            CGPoint pointConverted = [self convertPoint:point toView:subview];
            return [subview findTopMostViewForPoint:pointConverted];
        }
    }
    
    return self;
}

- (UIWindow *)topmostWindow
{
    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
    return topWindow;
}

@end

Can be used directly with any UIWindow as receiver or any UIView as receiver.

Solution 6 - Objective C

If you are adding a loading view (an activity indicator view for instance), make sure you have an object of UIWindow class. If you show an action sheet just before you show your loading view, the keyWindow will be the UIActionSheet and not UIWindow. And since the action sheet will go away, the loading view will go away with it. Or that's what was causing me problems.

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {
    // find uiwindow in windows
    NSArray *windows = [UIApplication sharedApplication].windows;
    for (UIWindow *window in windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
            keyWindow = window;
            break;
        }
    }
}

Solution 7 - Objective C

If your application only works in portrait orientation, this is enough:

[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]

And your view will not be shown over keyboard and status bar.

If you want to get a topmost view that over keyboard or status bar, or you want the topmost view can rotate correctly with devices, please try this framework:

https://github.com/HarrisonXi/TopmostView

It supports iOS7/8/9.

Solution 8 - Objective C

try this

UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];

Solution 9 - Objective C

Just use this code if you want to add a view above of everything in the screen.

[[UIApplication sharedApplication].keyWindow addSubView: yourView];

Solution 10 - Objective C

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {
    
    NSArray *windows = [UIApplication sharedApplication].windows;
    for (UIWindow *window in windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
            keyWindow = window;
            break;
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontypeoneerrorView Question on Stackoverflow
Solution 1 - Objective CsamvermetteView Answer on Stackoverflow
Solution 2 - Objective Can0View Answer on Stackoverflow
Solution 3 - Objective CKris MarkelView Answer on Stackoverflow
Solution 4 - Objective CloreanView Answer on Stackoverflow
Solution 5 - Objective ChfossliView Answer on Stackoverflow
Solution 6 - Objective CMiha HribarView Answer on Stackoverflow
Solution 7 - Objective CHarrison XiView Answer on Stackoverflow
Solution 8 - Objective CChandramaniView Answer on Stackoverflow
Solution 9 - Objective ChandiansomView Answer on Stackoverflow
Solution 10 - Objective Cuser12775146View Answer on Stackoverflow