获取对 iOS 应用程序中最顶层视图/窗口的引用

发布于 2024-09-26 06:16:10 字数 305 浏览 8 评论 0原文

我正在创建一个可重用的框架,用于在 iOS 应用程序中显示通知。我希望将通知视图添加到应用程序中其他所有内容的顶部,有点像 UIAlertView。当我初始化监听 NSNotification 事件并添加视图作为响应的管理器时,我需要获取对应用程序中最顶层视图的引用。这就是我现在所拥有的:

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

这适用于任何 iOS 应用程序还是它们是获取顶视图的更安全/更好的方法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

七度光 2024-10-03 06:16:10

每当我想在其他所有内容之上显示一些覆盖层时,我只需将其直接添加到应用程序窗口的顶部即可:

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

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]
撩发小公举 2024-10-03 06:16:10

问题有两个部分:顶部窗口,顶部窗口上的顶部视图。

所有现有的答案都错过了顶部窗口部分。但是 [[UIApplication sharedApplication] keyWindow] 不能保证是顶部窗口。

  1. 顶部窗口。一个应用程序中不太可能同时存在两个具有相同 windowLevel 的窗口,因此我们可以按 windowLevel 对所有窗口进行排序并获取最上面的窗口。

    UIWindow *topWindow = [[[UIApplication共享应用程序].windows排序ArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        返回 win1.windowLevel - win2.windowLevel;
    }] 最后一个对象];
    
  2. 顶部窗口的俯视图。只是为了完整。正如问题中已经指出的:

    UIView *topView = [[topWindow 子视图] lastObject];
    

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];
    
夜夜流光相皎洁 2024-10-03 06:16:10

通常,这将为您提供顶视图,但不能保证它对用户可见。例如,它可能位于屏幕之外,alpha 为 0.0,或者大小为 0x0。

也可能是 keyWindow 没有子视图,所以您应该首先测试它。这很不寻常,但也并非不可能。

UIWindow 是 UIView 的子类,因此如果您想确保您的通知对用户可见,您可以使用 addSubview: 将其直接添加到 keyWindow,它将立即成为最顶层的视图。我不确定这是否是您想要做的。 (根据你的问题,看来你已经知道这一点了。)

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.)

遇到 2024-10-03 06:16:10

实际上,您的应用程序中可能有多个 UIWindow。例如,如果屏幕上有键盘,则 [[UIApplication sharedApplication] windows] 将包含至少两个窗口(您的按键窗口和键盘窗口)。

因此,如果您希望视图出现在它们两个之上,那么您必须执行以下操作:(

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

假设lastObject包含具有最高windowLevel优先级的窗口)。

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).

别低头,皇冠会掉 2024-10-03 06:16:10

我坚持标题所述的问题,而不是讨论。哪个视图在任何给定点上都是可见的?

@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

可以直接与任何 UIWindow 作为接收器或任何 UIView 作为接收器一起使用。

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.

节枝 2024-10-03 06:16:10

如果您要添加加载视图(例如活动指示器视图),请确保您有 UIWindow 类的对象。如果您在显示加载视图之前显示操作表,则 keyWindow 将是 UIActionSheet 而不是 UIWindow。由于操作表将消失,加载视图也将随之消失。或者这就是给我带来问题的原因。

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;
        }
    }
}

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;
        }
    }
}
一张白纸 2024-10-03 06:16:10

如果您的应用程序仅在纵向方向上工作,这就足够了:

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

并且您的视图将不会显示在键盘和状态栏上。

如果您想获得键盘或状态栏上的最顶层视图,或者您希望最顶层视图可以随设备正确旋转,请尝试此框架:

https://github.com/HarrisonXi/TopmostView

支持iOS7/8/9。

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.

千笙结 2024-10-03 06:16:10

如果您想在屏幕上的所有内容上方添加视图,只需使用此代码即可。

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

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

[[UIApplication sharedApplication].keyWindow addSubView: yourView];
嗳卜坏 2024-10-03 06:16:10

试试这个

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

try this

UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
哭泣的笑容 2024-10-03 06:16:10
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;
        }
    }
}
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;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文