Tham chiếu đến chế độ xem / cửa sổ hàng đầu trong ứng dụng iOS


97

Tôi đang tạo một khung có thể sử dụng lại để hiển thị thông báo trong ứng dụng iOS. Tôi muốn các chế độ xem thông báo được thêm vào đầu mọi thứ khác trong ứng dụng, giống như UIAlertView. Khi tôi khởi động trình quản lý lắng nghe các sự kiện NSNotification và thêm các chế độ xem để phản hồi, tôi cần tham chiếu đến chế độ xem nhiều nhất trong ứng dụng. Đây là những gì tôi có vào lúc này:

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

Điều này sẽ hoạt động với bất kỳ ứng dụng iOS nào hay là cách an toàn hơn / tốt hơn của chúng để có được chế độ xem hàng đầu?

Câu trả lời:


36

Thông thường điều đó sẽ cung cấp cho bạn chế độ xem hàng đầu, nhưng không có gì đảm bảo rằng nó hiển thị cho người dùng. Nó có thể nằm ngoài màn hình, có alpha là 0.0, hoặc có thể có kích thước 0x0 chẳng hạn.

Cũng có thể là keyWindow không có lượt xem phụ, vì vậy bạn có thể nên kiểm tra điều đó trước. Điều này sẽ là bất thường, nhưng không phải là không thể.

UIWindow là một lớp con của UIView, vì vậy nếu bạn muốn đảm bảo rằng thông báo của mình được hiển thị cho người dùng, bạn có thể thêm nó trực tiếp vào keyWindow bằng cách sử dụng addSubview:và nó sẽ ngay lập tức được xem nhiều nhất. Tôi không chắc liệu đây có phải là điều bạn đang muốn làm hay không. (Dựa trên câu hỏi của bạn, có vẻ như bạn đã biết điều này.)


111

Bất cứ khi nào tôi muốn hiển thị một số lớp phủ trên mọi thứ khác, tôi chỉ cần thêm trực tiếp nó lên trên Cửa sổ ứng dụng:

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

9
Chỉ hoạt động theo hướng dọc .. bạn gotta quan tâm đến phép quay vv như thế này: stackoverflow.com/questions/2508630/...
hfossli

1
Tôi đang (null)sử dụng ứng dụng iOS-8 của mình (vấn đề về bảng phân cảnh?) Bạn có gợi ý nào không? Cảm ơn! (Lưu ý: (null)trả lại cả lúc viewDidLoadviewWillAppear:lúc. viewDidAppear:Quá muộn.
Olie

điều này có hoạt động không khi chúng tôi trình bày một bộ điều khiển chế độ xem ?. Chế độ xem phụ được thêm vào có hiển thị trên bộ điều khiển chế độ xem đã trình bày không?
Pratyusha Terli

Điều này sẽ không đi trên bàn phím, lastObject thì có.
Ser Pounce

Khung này có thể hoạt động theo mọi định hướng. Và sẽ đi trên bàn phím. github.com/HarrisonXi/TopmostView
Harrison Xi

47

Có hai phần của vấn đề: Cửa sổ trên cùng, chế độ xem trên cùng trên cửa sổ trên cùng.

Tất cả các câu trả lời hiện có đều bỏ lỡ phần cửa sổ trên cùng. Nhưng [[UIApplication sharedApplication] keyWindow]không được đảm bảo là cửa sổ trên cùng.

  1. Cửa sổ trên cùng. Rất ít khả năng sẽ có hai cửa sổ cùng windowLeveltồn tại cho một ứng dụng, vì vậy chúng ta có thể sắp xếp tất cả các cửa sổ theo windowLevelvà lấy một cửa sổ trên cùng.

    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
    
  2. Xem trên cùng trên cửa sổ trên cùng. Chỉ để được hoàn thành. Như đã được chỉ ra trong câu hỏi:

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

5
Giải pháp này ngừng làm việc cho tôi một lần UIAlertViews đi vào chơi - họ dường như để lại một đằng sau emtpy UIWindow, vì vậy tôi trở lại con ngườitopView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
Gereon

4
Điều này không hoạt động nếu bàn phím được nâng lên. Vì đó sẽ là cửa sổ trên cùng
entropy

@Gereon, hãy đảm bảo rằng bạn không có tham chiếu mạnh đến bất kỳ UIAlertView nào. Nếu đó không phải là một tham chiếu yếu, UIAlertOverlayWindow sẽ vẫn ở trong hệ thống phân cấp và được công nhận là cửa sổ chính, nhưng các lượt xem phụ được thêm vào nó sẽ không hiển thị.
beebcon

giá trị topWindow là không thích hợp trong trường hợp của iOS 8
Mehul Thakkar

11

Trên thực tế, có thể có nhiều hơn một UIWindow trong ứng dụng của bạn. Ví dụ: nếu bàn phím hiển thị trên màn hình thì [[UIApplication sharedApplication] windows]sẽ chứa ít nhất hai cửa sổ (cửa sổ bàn phím và cửa sổ bàn phím của bạn).

Vì vậy, nếu bạn muốn chế độ xem của mình xuất hiện trên cả hai thì bạn phải làm điều gì đó như:

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

(Giả sử lastObject chứa cửa sổ có mức ưu tiên windowLevel cao nhất).


Giá trị [[[UIApplication sharedApplication] windows] lastObject] không phù hợp trong trường hợp ios 8
Mehul Thakkar

Tôi đã bắt đầu sử dụng điều này, nhưng có vẻ như đôi khi cửa sổ bàn phím tồn tại nhưng không hiển thị và sau đó chế độ xem của tôi hoàn toàn không hiển thị!
teradyl

3

Tôi đang bám vào câu hỏi như tiêu đề nêu ra chứ không phải cuộc thảo luận. Chế độ xem nào có thể nhìn thấy trên cùng trên bất kỳ điểm nhất định nào?

@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

Có thể được sử dụng trực tiếp với bất kỳ UIWindow nào làm bộ thu hoặc bất kỳ UIView nào với tư cách bộ thu.


topWindow là cho giá trị sai trong trường hợp của iOS 8, bạn có thể vui lòng cập nhật câu trả lời của bạn dành cho iOS 8
Mehul Thakkar

1
Tôi không có thời gian để tìm hiểu. Nếu bạn có, bạn có thể tự do để cập nhật bài đăng này.
hfossli

1

Nếu bạn đang thêm chế độ xem đang tải (ví dụ: chế độ xem chỉ báo hoạt động), hãy đảm bảo rằng bạn có một đối tượng của lớp UIWindow. Nếu bạn hiển thị một trang hành động ngay trước khi bạn hiển thị chế độ xem đang tải của mình, thì đó keyWindowsẽ là UIActionSheetvà không UIWindow. Và vì trang hành động sẽ biến mất, chế độ xem tải sẽ biến mất cùng với nó. Hoặc đó là những gì đã gây ra cho tôi vấn đề.

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

1

Nếu ứng dụng của bạn chỉ hoạt động ở hướng dọc, điều này là đủ:

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

Và chế độ xem của bạn sẽ không được hiển thị trên bàn phím và thanh trạng thái.

Nếu bạn muốn có chế độ xem trên cùng qua bàn phím hoặc thanh trạng thái hoặc bạn muốn chế độ xem trên cùng có thể xoay chính xác với các thiết bị, vui lòng thử khung này:

https://github.com/HarrisonXi/TopmostView

Nó hỗ trợ iOS7 / 8/9.


0

Chỉ cần sử dụng mã này nếu bạn muốn thêm chế độ xem phía trên của mọi thứ trong màn hình.

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

0

thử cái này

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

Giới thiệu về thuộc tính windows: "Thuộc tính này chứa một mảng các đối tượng NSWindow tương ứng với tất cả các cửa sổ hiện có cho ứng dụng. Mảng này bao gồm tất cả các cửa sổ trên màn hình và ngoài màn hình, cho dù chúng có hiển thị trên bất kỳ không gian nào hay không. Không có gì đảm bảo về thứ tự của các cửa sổ trong mảng. "
Steven Fisher

0
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;
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.