Determine if a view is inside of a Popover view

2019-03-12 11:33发布

We have common views that we use in our application in many locations inside of UINavigationControllers. Occasionally the UINavigationControllers are inside of popover views. Now the views we put into the nav controllers modify their navigation controller's toolbar buttons and, in some cases, use custom buttons that we've created. We need to be able to figure out from the UIViewcontroller itself if the view is inside of a popoverview so we can display the correctly colored buttons.

We can easily get the Navigation controller reference from the UIViewController, using UIViewController.navigationController, but there doesn't seem to be anything for finding a UIPopoverController.

Does anyone have any good ideas for how to do this?

Thanks!

13条回答
放我归山
2楼-- · 2019-03-12 12:08

Swift 4 version (function can be added in 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
}
查看更多
混吃等死
3楼-- · 2019-03-12 12:11

In case that someone else is still looking for a solution i came up with one good enough for me.

Just override this method

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

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

    return controller.presentedViewController
}

Here is an example of YourViewController

class AdvisorHomeFilterViewController: UIViewController {

    // MARK: - Properties

    var isPopover = true
}

If it is popover it will not call 'viewControllerForAdaptivePresentationStyle' method and it will stay true, in case it is not popover it will set it to false.

查看更多
女痞
4楼-- · 2019-03-12 12:12

In iOS8 you can use popoverPresentationController property of UIViewController to check if it is contained in a popover presentation controller. From documentation, it returns: "The nearest ancestor in the view controller hierarchy that is a popover presentation controller. (read-only)"

查看更多
我欲成王,谁敢阻挡
5楼-- · 2019-03-12 12:12

By working with SpareTime's code I came to this, which works as expected. Nice code, nice solution:

Using the standard UISplitViewController example.

/* 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
查看更多
Ridiculous、
6楼-- · 2019-03-12 12:15

All the solutions above seems a little bit complicated. I'm using a variable called isInPopover which I set to true if the view controller is presented in a popover. In the view controller in popoverControllerDidDismissPopover or in viewWillDisappear I set the boolean value to false. It does work and is very simple.

查看更多
叼着烟拽天下
7楼-- · 2019-03-12 12:16

Modification of the accepted answer for iOS5.1 and newer:

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");

    }
}

** NOTE **

See comments about the reliability of this code.

查看更多
登录 后发表回答