确定视图是否在Popover视图中

mjd*_*dth 16 objective-c ipad uipopovercontroller

我们在我们的应用程序中使用了很多共同的视图UINavigationControllers.偶尔UINavigationControllers会在popover视图中.现在我们放入导航控制器的视图会修改导航控制器的工具栏按钮,在某些情况下,还会使用我们创建的自定义按钮.我们需要能够从UIViewcontroller自身中找出视图是否在popoverview中,以便我们可以显示正确颜色的按钮.

我们可以很容易地从UIViewController获取导航控制器参考UIViewController.navigationController,但是似乎找不到任何东西UIPopoverController.

有没有人对如何做到这一点有任何好的想法?

谢谢!

小智 8

由于阿尔乔姆说我们有UIPopoverPresentationControlleriOS8上.要确定视图是否在弹出窗口中,您可以使用其.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)
}
Run Code Online (Sandbox Code Playgroud)


Spa*_*ime 6

这是另一个解决方案; 定义一个只有一个方法的协议(例如PopoverSensitiveController):

#import "Foundation/Foundation.h"

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

想要知道它是否在弹出框中的视图控制器然后定义属性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属性即可.


Art*_*aev 5

在iOS8中,您可以使用UIViewController的popoverPresentationController属性来检查它是否包含在弹出窗口控制器中.从文档中,它返回:"视图控制器层次结构中最近的祖先是一个弹出式表示控制器.(只读)"

  • 这似乎只在显示视图控制器的视图后返回有效对象(即非零).即从`viewWillAppear:`返回给我的'nil` (3认同)

hyp*_*asm 3

我最近正在寻找一种方法来确定视图是否显示在弹出窗口中。这就是我想出的:

    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");
        }
Run Code Online (Sandbox Code Playgroud)

基本上,您会爬上视图的超级视图树,查看其超级视图中是否有 UIPopoverView。这里需要注意的是 UIPopoverView 类是一个未记录的私有类。我相信类名将来不会改变。YMMV。

在你的情况下:

theViewInQuestion =  theViewControllerInQuestion.view;
Run Code Online (Sandbox Code Playgroud)

我很想看看是否有其他人提出更好的解决方案。

  • 在代码中硬编码未记录的类名==坏主意。 (4认同)
  • 它是 AppStore 安全的,但对于 iOS 5.1 和 6,类名现在是 _UIPopoverView。 (2认同)