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

106,878

Solution 1

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 2

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 3

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 4

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

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.

Share:
106,878
typeoneerror
Author by

typeoneerror

I design businesses and the digital products that support them. For over 15 years, I've strategically planned and expertly executed digital experiences that delight, engage, and ultimately build stronger brands. I specialize in high-level technical strategies & full-stack development on web and mobile apps. I'm happiest solving tough technical challenges and building products with my favourite technologies including Ruby/Rails, Ember/Javascript, PHP, and Objective-C.

Updated on July 08, 2022

Comments

  • typeoneerror
    typeoneerror almost 2 years

    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?

  • Gereon
    Gereon over 11 years
    This solution stopped working for me once UIAlertViews came into play - they seem to leave an emtpy UIWindow behind, so I reverted back to topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
  • hfossli
    hfossli over 11 years
    Only works in portrait orientation.. You gotta care about rotations etc like this: stackoverflow.com/questions/2508630/…
  • entropy
    entropy almost 11 years
    This doesn't work if the keyboard is up. As that's gonna be the topmost window
  • beebcon
    beebcon almost 10 years
    @Gereon, make sure you're not holding a strong reference to any UIAlertView. If it isn't a weak reference, the UIAlertOverlayWindow will still be in the hierarchy and recognized as the key window, but subviews added to it won't display.
  • Mehul Thakkar
    Mehul Thakkar over 9 years
    topWindow is giving wrong value in case of iOS 8, Can you please update your answer for iOS 8
  • Mehul Thakkar
    Mehul Thakkar over 9 years
    topWindow value is not proper in case of iOS 8
  • Mehul Thakkar
    Mehul Thakkar over 9 years
    [[[UIApplication sharedApplication] windows] lastObject] value not proper in case of ios 8
  • hfossli
    hfossli over 9 years
    I don't have time to find out. If you do you are free to update this post.
  • Olie
    Olie over 9 years
    I'm getting (null) in my iOS-8 app (storyboards issue?) Any hints? Thanks! (Note: (null) returned both at viewDidLoad and viewWillAppear: time. viewDidAppear: is too late.
  • Pratyusha Terli
    Pratyusha Terli over 9 years
    does this work when we present a view controller?. Will the added subview shown over the presented view controller?
  • Ser Pounce
    Ser Pounce about 9 years
    This won't go above the keyboard, lastObject does though.
  • Harrison Xi
    Harrison Xi over 8 years
    This framework can work in all orientations. And will go above keyboard. github.com/HarrisonXi/TopmostView
  • teradyl
    teradyl about 8 years
    I started using this, but it seems sometimes the keyboard window exists but isn't showing, and then my view doesn't display at all!
  • Steven Fisher
    Steven Fisher over 6 years
    About the windows property: "This property contains an array of NSWindow objects corresponding to all currently existing windows for the app. The array includes all onscreen and offscreen windows, whether or not they are visible on any space. There is no guarantee of the order of the windows in the array."