iOS 애플리케이션에서 최상위보기 / 창에 대한 참조 얻기


97

iOS 애플리케이션에서 알림을 표시하기위한 재사용 가능한 프레임 워크를 만들고 있습니다. UIAlertView와 같이 애플리케이션의 다른 모든 것 위에 알림보기를 추가하고 싶습니다. NSNotification 이벤트를 수신하고 응답으로 뷰를 추가하는 관리자를 초기화 할 때 응용 프로그램의 최상위 뷰에 대한 참조를 가져와야합니다. 이것은 내가 현재 가지고있는 것입니다.

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

이것은 모든 iOS 응용 프로그램에서 작동합니까 아니면 상위 뷰를 얻는 더 안전하고 더 나은 방법입니까?

답변:


36

일반적으로 상위 뷰를 제공하지만 사용자에게 표시된다는 보장은 없습니다. 예를 들어 화면 밖에 있거나, 알파가 0.0이거나, 크기가 0x0 일 수 있습니다.

keyWindow에 하위보기가 없을 수도 있으므로 먼저 테스트해야합니다. 이것은 드문 일이지만 불가능하지는 않습니다.

UIWindow는 UIView의 하위 클래스이므로 알림이 사용자에게 표시되도록하려면을 사용하여 keyWindow에 직접 추가 addSubview:할 수 있으며 즉시 최상위 뷰가됩니다. 이것이 당신이하려는 일인지 확실하지 않습니다. (귀하의 질문에 따르면 이미 알고있는 것 같습니다.)


111

다른 모든 것 위에 오버레이를 표시하고 싶을 때마다 응용 프로그램 창 위에 직접 추가합니다.

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

9
세로 방향으로 만 작동합니다 .. 다음과 같이 회전 등에 대해 신경을 써야합니다. stackoverflow.com/questions/2508630/…
hfossli

1
나는군요 (null)내 아이폰 OS-8 앱에 (스토리 보드 문제?) 어떤 힌트를? 감사! (참고 : 및 시간에 (null)모두 반환 되었습니다. 너무 늦었습니다.viewDidLoadviewWillAppear:viewDidAppear:
Olie

뷰 컨트롤러를 제시 할 때 이것이 작동합니까?. 추가 된 서브 뷰가 제시된 뷰 컨트롤러 위에 표시됩니까?
Pratyusha Terli

이것은 키보드 위로 가지 않을 것이지만 lastObject는 그렇습니다.
Ser Pounce

이 프레임 워크는 모든 방향에서 작동 할 수 있습니다. 그리고 키보드 위로 이동합니다. github.com/HarrisonXi/TopmostView
해리슨 사이

47

문제에는 두 부분이 있습니다 : 상단 창, 상단 창 상단보기.

모든 기존 답변이 상단 창 부분을 놓쳤습니다. 그러나 [[UIApplication sharedApplication] keyWindow]상단 창이 보장되지는 않습니다.

  1. 상단 창. windowLevel앱에 대해 동일한 창이 두 개 공존 할 가능성은 거의 없으므로 모든 창을 정렬 windowLevel하여 최상위 창을 가져올 수 있습니다.

    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
  2. 상단 창에서 상위 뷰. 완전하게. 질문에서 이미 지적했듯이 :

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

5
그들이 emtpy의 UIWindow의 뒤에 떠날 것 같다 내가 다시 복귀 그래서 - UIAlertViews 플레이에 와서 일단이 솔루션은 나를 위해 작동이 중지topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
게 레온

4
키보드가 켜져 있으면 작동하지 않습니다. 그것이 최상단 창이 될 것이기 때문에
엔트로피

@Gereon, UIAlertView에 대한 강력한 참조를 보유하고 있지 않은지 확인하십시오. 약한 참조가 아닌 경우 UIAlertOverlayWindow는 여전히 계층 구조에 있고 키 창으로 인식되지만 여기에 추가 된 하위 뷰는 표시되지 않습니다.
beebcon 2014

iOS 8의 경우 topWindow 값이 적절하지 않음
Mehul Thakkar

11

실제로 응용 프로그램에 둘 이상의 UIWindow가있을 수 있습니다. 예를 들어 키보드가 화면에있는 경우 [[UIApplication sharedApplication] windows]최소한 두 개의 창 (키 창 및 키보드 창)이 포함됩니다.

따라서 뷰가 둘 다 위에 나타나도록하려면 다음과 같이해야합니다.

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

(lastObject에 windowLevel 우선 순위가 가장 높은 창이 포함되어 있다고 가정합니다.)


[[[UIApplication sharedApplication] windows] ios 8의 경우 lastObject] 값이 적절하지 않음
Mehul Thakkar

나는 이것을 사용하기 시작했지만 때로는 키보드 창이 존재하지만 표시되지 않는 것처럼 보이며 내보기가 전혀 표시되지 않습니다!
teradyl

3

나는 토론이 아니라 제목이 말하는대로 질문을 고수하고있다. 주어진 지점에서 어떤 뷰가 상단에 표시됩니까?

@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와 함께 직접 사용할 수 있습니다.


topWindow는 아이폰 OS (8)에 대한 답변을 업데이트하십시오 수, 아이폰 OS 8의 경우 잘못된 값을주고있다
Mehul Thakkar

1
알아낼 시간이 없습니다. 그렇게한다면이 게시물을 자유롭게 업데이트 할 수 있습니다.
hfossli

1

로드 뷰 (예 : 활동 표시기 뷰)를 추가하는 경우 UIWindow 클래스의 객체가 있는지 확인하십시오. 로드 뷰를 표시하기 직전에 작업 시트를 표시하면 keyWindowUIActionSheet이고는 아닙니다 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;
        }
    }
}

1

응용 프로그램이 세로 방향으로 만 작동하는 경우 다음으로 충분합니다.

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

그리고보기는 키보드와 상태 표시 줄에 표시되지 않습니다.

키보드 또는 상태 표시 줄 위에있는 최상위보기를 원하거나 장치에서 최상위보기를 올바르게 회전하려면 다음 프레임 워크를 사용해보세요.

https://github.com/HarrisonXi/TopmostView

iOS7 / 8 / 9를 지원합니다.


0

화면의 모든 항목 위에보기를 추가하려면이 코드를 사용하십시오.

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

0

이 시도

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

windows 속성 정보 : "이 속성은 앱의 현재 존재하는 모든 창에 해당하는 NSWindow 객체의 배열을 포함합니다. 배열에는 모든 공간에 표시되는지 여부에 관계없이 모든 온 스크린 및 오프 스크린 창이 포함됩니다. 순서에 대한 보장은 없습니다. 배열의 창의 수. "
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;
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.