จะทราบได้อย่างไรว่ามองเห็นวิวของ UIViewController


569

ฉันมีแอปพลิเคชันแถบแท็บที่มีมุมมองมากมาย มีวิธีที่จะรู้ได้หรือไม่ว่าในUIViewControllerปัจจุบันนั้นสามารถมองเห็นได้จากภายในUIViewController? (มองหาอสังหาริมทรัพย์)


คำตอบ:


1097

คุณสมบัติหน้าต่างของมุมมองไม่เป็นศูนย์ถ้ามองเห็นได้ในขณะนี้ดังนั้นให้ตรวจสอบมุมมองหลักในตัวควบคุมมุมมอง:

การเรียกใช้เมธอดviewทำให้มุมมองโหลด (หากไม่ได้โหลด) ซึ่งไม่จำเป็นและอาจไม่พึงปรารถนา มันจะเป็นการดีกว่าที่จะตรวจสอบก่อนเพื่อดูว่ามันโหลดแล้ว ฉันได้เพิ่มการเรียกไปยัง isViewLoaded เพื่อหลีกเลี่ยงปัญหานี้

if (viewController.isViewLoaded && viewController.view.window) {
    // viewController is visible
}

ตั้งแต่ iOS9 มันง่ายขึ้น:

if viewController.viewIfLoaded?.window != nil {
    // viewController is visible
}

หรือถ้าคุณมี UINavigationController จัดการมุมมองตัวควบคุมคุณสามารถตรวจสอบคุณสมบัติvisibleViewController


11
ปัญหาหนึ่งที่มีคุณสมบัติ visibleViewControllee ของ UINavigationController เป็นกรณีที่ visibleViewController ของคุณนำเสนอตัวควบคุมมุมมอง modal ในกรณีนั้นมุมมองกิริยากลายเป็น visibleViewController ซึ่งอาจไม่พึงประสงค์ คุณจะจัดการกับสิ่งนั้นอย่างไร
Moshe

12
นี่อาจเป็นที่ชัดเจนสำหรับทุกคน แต่สำหรับฉันรหัสต้องเป็นตัวเอง isViewLoaded && self.view.window
JeffB6688

85
โปรดใช้ความระมัดระวังในการสรุปแนวทางแก้ไขนี้สำหรับสถานการณ์อื่น ตัวอย่างเช่นหากคุณใช้ UIPageViewController มุมมองสำหรับ UIViewControllers ที่ไม่ใช่หน้าปัจจุบันอาจยังคงมีคุณสมบัติหน้าต่างที่ไม่ใช่แบบศูนย์เนื่องจากกำลังแสดงผลนอกหน้าจอ ในกรณีนี้ฉันประสบความสำเร็จในการสร้างคุณสมบัติ 'isCurrentlyVisible' ของตัวเองซึ่งได้รับการตั้งค่าใน viewDidAppear และ viewDidDisappear
evanflash

4
@Moshe topViewControllerในกรณีที่ใช้
ma11hew28

3
โปรดทราบว่าคำตอบนี้ไม่ได้พูดอะไรเกี่ยวกับการมองเห็นที่แท้จริง ตัวอย่างเช่นหากแอปอยู่ในพื้นหลังด้านบนคำสั่ง IF จะบอกว่าใช่ในขณะที่มุมมองไม่สามารถมองเห็นได้
Marek J.

89

นี่คือโซลูชันของ @ progrmr เป็นUIViewControllerหมวดหมู่:

// UIViewController+Additions.h

@interface UIViewController (Additions)

- (BOOL)isVisible;

@end


// UIViewController+Additions.m

#import "UIViewController+Additions.h"

@implementation UIViewController (Additions)

- (BOOL)isVisible {
    return [self isViewLoaded] && self.view.window;
}

@end

47

มีปัญหาสองสามข้อที่มีวิธีแก้ไขปัญหาข้างต้น ตัวอย่างเช่นถ้าคุณใช้ก. UISplitViewControllerมุมมองหลักจะส่งกลับค่าจริงเสมอ

if(viewController.isViewLoaded && viewController.view.window) {
    //Always true for master view in split view controller
}

ให้ใช้วิธีการง่ายๆนี้ซึ่งดูเหมือนว่าจะทำงานได้ดีที่สุดหากไม่ใช่ทุกกรณี:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    //We are now invisible
    self.visible = false;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    //We are now visible
    self.visible = true;
}

1
สิ่งนี้ยังคงเป็นจริงใน xCode 7.1.1 หรือไม่ ต้นแบบใน UISplitViewController ของฉันกำลังส่งคืน NO สำหรับ viewController.view.window ฉันอาจจะทำสิ่งผิดปกติ แต่ฉันค่อนข้างมั่นใจว่าเป็นกรณีนี้
SAHM

44

สำหรับผู้ที่กำลังมองหาคำตอบเวอร์ชั่นSwift 2.2 :

if self.isViewLoaded() && (self.view.window != nil) {
     // viewController is visible
}

และรวดเร็ว 3 :

if self.isViewLoaded && (self.view.window != nil) {
         // viewController is visible
}

ไม่แน่ใจว่าทำไม แต่ฉันพบว่าการทำ self.view.window! = nil ทำให้มันไม่ทำงานแม้ว่า self.isViewLoaded จะเป็นจริง เมื่อลบออกแล้วจะทำงานได้ดี
คา Montoya

สิ่งนี้ใช้ได้กับฉันใน viewDidAppear เท่านั้น เมื่อฉันเพิ่มสิ่งนี้ลงใน viewWillAppear self.view.window! = ไม่มีมาเสมอไม่มี
Lance Samaria

29

สำหรับการนำเสนอแบบเต็มหน้าจอหรือมากกว่าบริบทคำว่า "มองเห็นได้" อาจหมายถึงมันอยู่ด้านบนของตัวควบคุมมุมมองสแต็กหรือมองเห็นได้ แต่ครอบคลุมโดยตัวควบคุมมุมมองอื่น

ในการตรวจสอบว่าตัวควบคุมมุมมอง "เป็นตัวควบคุมมุมมองด้านบน" ค่อนข้างแตกต่างจาก "มองเห็นได้" คุณควรตรวจสอบสแตกตัวควบคุมมุมมองของตัวควบคุมการนำทางของตัวควบคุมมุมมอง

ฉันเขียนโค้ดเพื่อแก้ปัญหานี้:

extension UIViewController {
    public var isVisible: Bool {
        if isViewLoaded {
            return view.window != nil
        }
        return false
    }

    public var isTopViewController: Bool {
        if self.navigationController != nil {
            return self.navigationController?.visibleViewController === self
        } else if self.tabBarController != nil {
            return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
        } else {
            return self.presentedViewController == nil && self.isVisible
        }
    }
}

โพสต์ดี! FYI isViewLoadedเป็นคุณสมบัติตั้งแต่ Swift 3.0
Yuchen Zhong

28

คุณต้องการที่จะใช้UITabBarControllerของselectedViewControllerสถานที่ให้บริการ ตัวควบคุมมุมมองทั้งหมดที่แนบกับตัวควบคุมแถบแท็บมีtabBarControllerชุดคุณสมบัติดังนั้นคุณสามารถทำได้จากภายในรหัสตัวควบคุมมุมมองใด ๆ :

if([[[self tabBarController] selectedViewController] isEqual:self]){
     //we're in the active controller
}else{
     //we are not
}

2
สิ่งนี้จะไม่ทำงานหากตัวควบคุมมุมมองอยู่ภายในตัวควบคุมการนำทางและตัวควบคุมนั้นถูกเพิ่มเข้าไปในตัวควบคุมแถบของแท็บ การเรียกไปยัง SelectedViewController จะส่งคืนตัวควบคุมการนำทางไม่ใช่ตัวควบคุมมุมมองปัจจุบัน
Anton Holmberg

2
@AntonHolmberg ในกรณีนี้รับคอนโทรลเลอร์มุมมองที่มองเห็นได้ดังนี้:((UINavigationController *)self.tabBarController.selectedViewController).visibleViewController
ma11hew28

หรือแม้กระทั่งใช้คุณสมบัติ 'self.tabBarController.selectedIndex' ถ้าเราไปไกลขนาดนี้แล้ว
Vladimir Shutyuk

12

ฉันสร้างส่วนขยายอย่างรวดเร็วตามคำตอบของ @ progrmr

มันช่วยให้คุณตรวจสอบได้ง่ายว่า a UIViewControllerอยู่บนหน้าจอไหม

if someViewController.isOnScreen {
    // Do stuff here
}

ส่วนขยาย:

//
//  UIViewControllerExtension.swift
//

import UIKit

extension UIViewController{
    var isOnScreen: Bool{
        return self.isViewLoaded() && view.window != nil
    }
}

7

สำหรับวัตถุประสงค์ของฉันในบริบทของตัวควบคุมมุมมองคอนเทนเนอร์ฉันพบว่า

- (BOOL)isVisible {
    return (self.isViewLoaded && self.view.window && self.parentViewController != nil);
}

ทำได้ดี.


3

หากคุณใช้ UINavigationController และต้องการจัดการกับมุมมองแบบโมดอลต่อไปนี้คือสิ่งที่ฉันใช้:

#import <objc/runtime.h>

UIViewController* topMostController = self.navigationController.visibleViewController;
if([[NSString stringWithFormat:@"%s", class_getName([topMostController class])] isEqualToString:@"NAME_OF_CONTROLLER_YOURE_CHECKING_IN"]) {
    //is topmost visible view controller
}

2
ฉันพบวิธีนี้เชื่อถือได้มากกว่าคำตอบที่ยอมรับเมื่อมีตัวควบคุมการนำทาง สิ่งนี้สามารถย่อให้เป็น: ถ้า ([self.navigationController.visibleViewController isKindOfClass: [ระดับตัวเอง]]) {
Darren

3

วิธีการที่ฉันใช้สำหรับตัวควบคุมมุมมองการนำเสนอ modal คือการตรวจสอบคลาสของตัวควบคุมที่นำเสนอ หากตัวควบคุมมุมมองที่นำเสนอViewController2นั้นฉันจะรันรหัสบางอย่าง

UIViewController *vc = [self presentedViewController];

if ([vc isKindOfClass:[ViewController2 class]]) {
    NSLog(@"this is VC2");
}

3

UIViewController.hผมพบว่าผู้ที่อยู่ในฟังก์ชั่น

/*
  These four methods can be used in a view controller's appearance callbacks to determine if it is being
  presented, dismissed, or added or removed as a child view controller. For example, a view controller can
  check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear:
  method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]).
*/

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);

บางทีฟังก์ชั่นด้านบนสามารถตรวจจับการViewControllerปรากฏหรือไม่


3

XCode 6.4, สำหรับ iOS 8.4, เปิดใช้งาน ARC

เห็นได้ชัดว่าหลายวิธีในการทำมัน สิ่งที่ได้ผลสำหรับฉันคือ ...

@property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow

สามารถใช้ในมุมมองตัวควบคุมใด ๆ ในวิธีต่อไปนี้

[self.view.window isKeyWindow]

ถ้าคุณเรียกคุณสมบัตินี้-(void)viewDidLoadว่าคุณได้ 0 แล้วถ้าคุณเรียกสิ่งนี้หลังจาก-(void)viewDidAppear:(BOOL)animatedคุณได้ 1

หวังว่านี่จะช่วยใครซักคน ขอบคุณ! ไชโย


3

หากคุณใช้ตัวควบคุมการนำทางและต้องการทราบว่าคุณอยู่ในตัวควบคุมที่ใช้งานอยู่และระดับสูงสุดให้ใช้:

if navigationController?.topViewController == self {
    // Do something
}

คำตอบนี้ขึ้นอยู่กับความคิดเห็นของ@mattdipasquale

หากคุณมีสถานการณ์ที่ซับซ้อนขึ้นให้ดูคำตอบอื่น ๆ ด้านบน


สิ่งนี้จะไม่ถูกเรียกใช้หากแอปทำงานในพื้นหลังและทำงานเบื้องหน้า ฉันกำลังมองหาวิธีแก้ปัญหาที่ฉันสามารถตรวจสอบว่าผู้ใช้สามารถดูตัวควบคุมมุมมองได้หรือไม่ ผู้ใช้สามารถแบ็คกราวด์แอปได้สองสามวันและเมื่อมันกลับมาทำงานเบื้องหน้าฉันต้องการอัปเดต UI โปรดแจ้งให้เราทราบหากคุณสามารถช่วยได้
bibscy


0

ฉันต้องการสิ่งนี้เพื่อตรวจสอบว่าตัวควบคุมมุมมองเป็นตัวควบคุมที่ดูอยู่ในปัจจุบันหรือไม่ฉันผ่านการตรวจสอบว่ามีตัวควบคุมมุมมองที่แสดงหรือผลักผ่านตัวนำทางฉันกำลังโพสต์ไว้ในกรณีที่ใครก็ตามต้องการโซลูชันดังกล่าว

if presentedViewController != nil || navigationController?.topViewController != self {
      //Viewcontroller isn't viewed
}else{
     // Now your viewcontroller is being viewed 
}

0

ผมใช้นามสกุลนี้มีขนาดเล็กในสวิฟท์ 5ซึ่งทำให้มันง่ายและง่ายต่อการตรวจสอบวัตถุใด ๆ ที่เป็นสมาชิกของUIView

extension UIView {
    var isVisible: Bool {
        guard let _ = self.window else {
            return false
        }
        return true
    }
}

จากนั้นฉันก็ใช้มันเป็นคำสั่งง่ายๆถ้าตรวจสอบ ...

if myView.isVisible {
    // do something
}

ฉันหวังว่ามันจะช่วย! :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.