การอ้างอิงถึงมุมมอง / หน้าต่างด้านบนสุดในแอปพลิเคชัน 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)ในแอป iOS-8 ของฉัน (มีปัญหาสตอรี่บอร์ด) มีคำแนะนำอะไรไหม ขอบคุณ! (หมายเหตุ: (null)ส่งคืนทั้งในเวลาviewDidLoadและviewWillAppear:เวลา viewDidAppear:สายเกินไป
Olie

ใช้งานได้หรือไม่เมื่อเรานำเสนอตัวควบคุมมุมมอง? มุมมองย่อยที่เพิ่มจะแสดงเหนือตัวควบคุมมุมมองที่นำเสนอหรือไม่
Pratyusha Terli

สิ่งนี้จะไม่อยู่เหนือแป้นพิมพ์ แต่ lastObject ทำ
Ser Pounce

กรอบงานนี้สามารถทำงานได้ในทุกแนว และจะขึ้นเหนือแป้นพิมพ์ github.com/HarrisonXi/TopmostView
Harrison Xi

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
โซลูชันนี้หยุดทำงานสำหรับฉันเมื่อ UIAlertViews เข้ามาเล่น - ดูเหมือนว่าจะทิ้ง UIWindow ที่ว่างเปล่าไว้ข้างหลังดังนั้นฉันจึงเปลี่ยนกลับไปเป็นtopView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
Gereon

4
จะไม่ได้ผลหากคีย์บอร์ดเปิดอยู่ นั่นจะเป็นหน้าต่างที่อยู่บนสุด
เอนโทรปี

@Gereon ตรวจสอบให้แน่ใจว่าคุณไม่ได้มีการอ้างอิงที่ชัดเจนกับ UIAlertView ใด ๆ หากไม่ใช่ข้อมูลอ้างอิงที่ไม่ชัดเจน UIAlertOverlayWindow จะยังคงอยู่ในลำดับชั้นและรับรู้ว่าเป็นหน้าต่างหลัก แต่มุมมองย่อยที่เพิ่มเข้าไปจะไม่แสดง
beebcon

ค่า topWindow ไม่เหมาะสมในกรณีของ iOS 8
Mehul Thakkar

11

จริงๆแล้วอาจมี UIWindow มากกว่าหนึ่งรายการในแอปพลิเคชันของคุณ ตัวอย่างเช่นหากแป้นพิมพ์อยู่บนหน้าจอ[[UIApplication sharedApplication] windows]จะมีอย่างน้อยสองหน้าต่าง (หน้าต่างคีย์และหน้าต่างแป้นพิมพ์ของคุณ)

ดังนั้นหากคุณต้องการให้มุมมองของคุณปรากฏบนยอดของทั้งคู่คุณต้องทำสิ่งต่อไปนี้:

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

(สมมติว่า lastObject มีหน้าต่างที่มีลำดับความสำคัญ windowLevel สูงสุด)


[[[UIApplication sharedApplication] windows] lastObject] ค่าไม่เหมาะสมในกรณีของ ios 8
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 ให้ค่าผิดในกรณีของ iOS 8 โปรดอัปเดตคำตอบสำหรับ iOS 8
Mehul Thakkar

1
ฉันไม่มีเวลาหา หากคุณมีอิสระที่จะอัปเดตโพสต์นี้
hfossli

1

หากคุณกำลังเพิ่มมุมมองการโหลด (เช่นมุมมองตัวบ่งชี้กิจกรรม) ตรวจสอบให้แน่ใจว่าคุณมีออบเจ็กต์ของคลาส 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;
        }
    }
}

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.