Определите, находится ли представление внутри представления Popover - PullRequest
16 голосов
/ 16 ноября 2010

У нас есть общие представления, которые мы используем в нашем приложении во многих местах внутри UINavigationControllers. Иногда UINavigationController находятся внутри представлений popover. Теперь представления, которые мы помещаем в контроллеры nav, изменяют кнопки панели инструментов их контроллера навигации и, в некоторых случаях, используют созданные нами пользовательские кнопки. Мы должны быть в состоянии выяснить из самого UIViewcontroller, является ли представление внутри всплывающего окна, чтобы мы могли отображать кнопки правильного цвета.

Мы можем легко получить ссылку на контроллер навигации из UIViewController, используя UIViewController.navigationController, но, похоже, ничего не найдено для поиска UIPopoverController.

У кого-нибудь есть хорошие идеи, как это сделать?

Спасибо!

Ответы [ 13 ]

7 голосов
/ 27 июля 2015

Как сказал Артем, у нас UIPopoverPresentationController с iOS8 .Чтобы определить, является ли представление всплывающим, вы можете использовать его свойство .arrowDirection, например.

Проверьте его в viewWillApear() представленного контроллера представления:

// get it from parent NavigationController
UIPopoverPresentationController* popoverPresentationVC = self.parentViewController.popoverPresentationController; 
if (UIPopoverArrowDirectionUnknown > popoverPresentationVC.arrowDirection) {
// presented as popover
} else {
// presented as modal view controller (on iPhone)
}
6 голосов
/ 24 апреля 2011

Вот еще одно решение; определить протокол (например, PopoverSensitiveController), который имеет только один метод:

#import "Foundation/Foundation.h"

@protocol PopoverSensitiveController 
-(void) setIsInPopover:(BOOL) inPopover;
@end

Контроллер представления, который хочет знать, находится ли он в popover, затем определяет свойство isInPopover; например:

#import 
#import "PopoverSensitiveController.h"

#pragma mark -
#pragma mark Interface
@interface MyViewController : UIViewController  {
}

#pragma mark -
#pragma mark Properties
@property (nonatomic) BOOL isInPopover;

#pragma mark -
#pragma mark Instance Methods
...other stuff...
@end

Наконец, в делегате splitView (предполагается, что ваше приложение использует контроллер разделения представления):

#import "MySplitViewControllerDelegate.h"
#import "SubstitutableDetailViewController.h"
#import "PopoverSensitiveController.h"

#pragma mark -
#pragma mark Implementation
@implementation MySplitViewControllerDelegate

#pragma mark -
#pragma mark UISplitViewControllerDelegate protocol methods
-(void) splitViewController:(UISplitViewController *) splitViewController willHideViewController:(UIViewController *) aViewController withBarButtonItem:(UIBarButtonItem *) barButtonItem forPopoverController:(UIPopoverController *) pc {

  // Keep references to the popover controller and the popover button, and tell the detail view controller to show the button
  popoverController = [pc retain];
  popoverButtonItem = [barButtonItem retain];
  if ([[splitViewController.viewControllers objectAtIndex:1] respondsToSelector:@selector(showRootPopoverButtonItem:)]) {
      UIViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
      [detailViewController showRootPopoverButtonItem:barButtonItem];
  }
  if ([[splitViewController.viewControllers objectAtIndex:1] respondsToSelector:@selector(showRootPopoverButtonItem:)]) {
      UIViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
      [detailViewController showRootPopoverButtonItem:barButtonItem];
  }

  // If the view controller wants to know, tell it that it is a popover
  if ([aViewController respondsToSelector:@selector(setIsInPopover:)]) {
    [(id) aViewController setIsInPopover:YES];
  }

  // Make sure the proper view controller is in the popover controller and the size is as requested
  popoverController.contentViewController = aViewController;
  popoverController.popoverContentSize = aViewController.contentSizeForViewInPopover;

}

-(void) splitViewController:(UISplitViewController *) splitViewController willShowViewController:(UIViewController *) aViewController invalidatingBarButtonItem:(UIBarButtonItem *) barButtonItem {

  // Tell the detail view controller to hide the button.
  if ([[splitViewController.viewControllers objectAtIndex:1] respondsToSelector:@selector(invalidateRootPopoverButtonItem:)]) {
    UIViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
    [detailViewController invalidateRootPopoverButtonItem:barButtonItem];
  }

  // If the view controller wants to know, tell it that it is not in a popover anymore
  if ([aViewController respondsToSelector:@selector(setIsInPopover:)]) {
    [(id) aViewController setIsInPopover:NO];
  }

  // Now clear out everything
  [popoverController release];
  popoverController = nil;
  [popoverButtonItem release];
  popoverButtonItem = nil;

}

-(void) setPopoverButtonForSplitViewController:(UISplitViewController *) splitViewController {

  // Deal with the popover button
  UIViewController *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
  [detailViewController showRootPopoverButtonItem:popoverButtonItem];

  // If the view controller wants to know, tell it that it is a popover (initialize the controller properly)
  if ([[splitViewController.viewControllers objectAtIndex:0] respondsToSelector:@selector(setIsInPopover:)]) {
    [(id) [splitViewController.viewControllers objectAtIndex:0] setIsInPopover:YES];
  }

}

Тогда, где бы вы ни находились в контроллере представления, чтобы узнать, находитесь ли вы в поповере, просто используйте свойство isInPopover.

5 голосов
/ 13 сентября 2014

В iOS8 вы можете использовать свойство popoverPresentationController UIViewController, чтобы проверить, содержится ли оно в контроллере представления всплывающего окна.Из документации возвращается: «Ближайший предок в иерархии контроллера представления, который является контроллером представления всплывающего окна. (Только для чтения)» *

3 голосов
/ 25 октября 2012

Модификация принятого ответа для iOS5.1 и новее:

for (UIView *v = self.view; v.superview != nil; v=v.superview) { 

    if ([v isKindOfClass:[NSClassFromString(@"_UIPopoverView") class]]) {

        NSLog(@"\n\n\nIM IN A POPOVER!\n\n\n\n");

    }
}

** ПРИМЕЧАНИЕ **

См. Комментарии о надежности этого кода.

3 голосов
/ 17 ноября 2010

Недавно я искал способ определить, отображается ли представление во всплывающем окне.Вот что я придумал:

    UIView *v=theViewInQuestion;        
    for (;v.superview != nil; v=v.superview) {
        if (!strcmp(object_getClassName(v), "UIPopoverView")) {
            NSLog(@"\n\n\nIM IN A POPOVER!\n\n\n\n");
        }

По сути, вы взбираетесь на дерево суперпредставлений представления, чтобы посмотреть, является ли какой-либо из его суперпредставлений UIPopoverView.Единственное предостережение в том, что класс UIPopoverView является недокументированным закрытым классом.Я полагаюсь на то, что имя класса не изменится в будущем.YMMV.

В вашем случае:

theViewInQuestion =  theViewControllerInQuestion.view;

Мне было бы интересно узнать, придумает ли кто-нибудь еще лучшее решение.

2 голосов
/ 21 октября 2015

Мой подход к этому: (доступно с iOS 8 или выше)

- (BOOL)isContainedInPopover
{
    UIPopoverPresentationController* popoverPresentationVC = self.parentViewController.popoverPresentationController;
    return (popoverPresentationVC != nil);
}

Контроллер родительского представления будет контроллером навигации, который, если он находится внутри поповера, будет иметь свойство, отличное от nil popoverPresentationController.

1 голос
/ 20 февраля 2019

На тот случай, если кто-то еще ищет решение, я нашел достаточно подходящее для меня.

Просто переопределите этот метод

func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {

    (controller.presentedViewController as? YourViewControler).isPopover = false

    return controller.presentedViewController
}

Вот пример YourViewController

class AdvisorHomeFilterViewController: UIViewController {

    // MARK: - Properties

    var isPopover = true
}

Если это popover, он не будет вызывать метод 'viewControllerForAdaptivePresentationStyle' и останется истинным, в случае, если это не popover, он установит его в false.

1 голос
/ 03 марта 2012

Работая с кодом SpareTime, я пришел к этому, который работает, как и ожидалось.Хороший код, хорошее решение:

Используя стандартный пример UISplitViewController.

/* MasterViewController.h */

#import "UIPopoverViewDelegate.h"

@interface masterViewController : UITableViewController <UIPopoverViewDelegate>
@property (nonatomic) BOOL isInPopover;
@end

/* MasterViewController.m */

#import "MasterViewController.h"

@implementation MasterViewController

@synthesize isInPopover = _isInPopover;

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

    if (self.isInPopover)
    {
        // Code for appearing in popover
    }
    else
    {
        // Code for not appearing in popover
    }
}

@end

/* DetailViewController.h */

#import "UIPopoverViewDelegate.h"

@interface detailViewController : UIViewController <UISplitViewControllerDelegate>
@end

/* DetailViewController.m */

#import "DetailViewController.h"

@implementation detailViewController

- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{

    /* This method is called when transitioning to PORTRAIT orientation. */

    UIViewController *hiddenViewController = [(UINavigationController *)viewController childViewControllers].lastObject;

    if ([hiddenViewController respondsToSelector:@selector(setIsInPopover:)])
        [(id <UIPopoverViewDelegate>)hiddenViewController setIsInPopover:YES];
}

- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{

    /* This method is called when transitioning to LANDSCAPE orientation. */

    UIViewController *shownViewController = [(UINavigationController *)viewController childViewControllers].lastObject;

    if ([shownViewController respondsToSelector:@selector(setIsInPopover:)])
        [(id <UIPopoverViewDelegate>)shownViewController setIsInPopover:NO];
}

@end

/* UIPopoverViewDelegate.h */

@protocol UIPopoverViewDelegate
@required
-(void)setIsInPopover:(BOOL)inPopover;
@end
0 голосов
/ 29 ноября 2018

Swift 4 версия (функция может быть добавлена ​​в extension UIViewController):

func isInPopover() -> Bool {
    guard UIDevice.current.userInterfaceIdiom == .pad else { return false }

    var checkingVC: UIViewController? = self
    repeat {
        if checkingVC?.modalPresentationStyle == .popover {
            return true
        }
        checkingVC = checkingVC?.parent
    } while checkingVC != nil
    return false
}
0 голосов
/ 27 апреля 2016

Поскольку self.popoverPresentationController создается лениво в последних версиях iOS, следует проверить, равняется ли ноль self.popoverPresentationController.presentingViewController, если нет, то это будет означать, что self в настоящее время представлено в поповер.

...