我们在UINavigationControllers
内的许多位置都有我们的应用程序中使用的常见视图。偶尔UINavigationController
是在popover视图中。现在我们放入导航控制器的视图会修改导航控制器的工具栏按钮,在某些情况下,还会使用我们创建的自定义按钮。如果视图位于popoverview中,我们需要能够从UIViewcontroller
本身找出来,以便我们可以显示正确颜色的按钮。
我们可以使用UIViewController.navigationController
从UIViewController轻松获取导航控制器参考,但似乎找不到UIPopoverController
。
有没有人对如何做到这一点有任何好的想法?
谢谢!
答案 0 :(得分:7)
正如Artem所说,自 iOS8 以来我们已UIPopoverPresentationController
。要确定视图是否在弹出窗口中,您可以使用其.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)
}
答案 1 :(得分:6)
这是另一种解决方案;定义一个只有一个方法的协议(例如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属性。
答案 2 :(得分:5)
在iOS8中,您可以使用UIViewController的popoverPresentationController属性来检查它是否包含在弹出式表示控制器中。从文档中,它返回:"视图控制器层次结构中最近的祖先,它是一个弹出式表示控制器。 (只读)"
答案 3 :(得分: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");
}
基本上你爬上视图的超级视图树,看看它的任何超级视图是否是UIPopoverView。这里要注意的是,类UIPopoverView是一个未记录的私有类。我依赖于类名在将来不会改变的事实。 YMMV。
在你的情况下:
theViewInQuestion = theViewControllerInQuestion.view;
我有兴趣看看是否有其他人想出更好的解决方案。
答案 4 :(得分:3)
修改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");
}
}
**注意**
请参阅有关此代码可靠性的评论。
答案 5 :(得分:2)
我的方法:(适用于iOS 8或更高版本)
- (BOOL)isContainedInPopover
{
UIPopoverPresentationController* popoverPresentationVC = self.parentViewController.popoverPresentationController;
return (popoverPresentationVC != nil);
}
父视图控制器将是导航控制器,如果在弹出窗口内,将具有非零popoverPresentationController
属性。
答案 6 :(得分:1)
通过使用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
答案 7 :(得分:1)
万一其他人仍在寻找解决方案,我想出一个对我来说足够好的解决方案。
只需重写此方法
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'方法,它将保持为true;如果不是popover,则将其设置为false。
答案 8 :(得分:0)
如果视图不是显示在弹出窗口中,我想在视图中放置一个按钮。我知道弹出窗口的宽度,因为我只是设置它。所以我可以测试我是否在iPad上以及框架的宽度是否与我设置的相同。
- (void)viewWillAppear:(BOOL)animated {
[self setContentSizeForViewInPopover:CGSizeMake(400, 500)];
NSInteger frameWidth = self.view.frame.size.width;
//Let you go back to the game if on an iPod.
if ( ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) && !(frameWidth == 400) ) { ---code to display a button --}
答案 9 :(得分:0)
所有这些'精确的类名匹配方法'很容易失败,即使是苹果公司将做出的最微小的改变也会中断。同时做一个char-vars和神秘的for-loop也不是一个适合我风格的解决方案。
我使用以下代码:
- (BOOL) isInPopOver {
UIView *currentView = self.view;
while( currentView ) {
NSString *classNameOfCurrentView = NSStringFromClass([currentView class]);
NSLog( @"CLASS-DETECTED: %@", classNameOfCurrentView );
NSString *searchString = @"UIPopoverView";
if( [classNameOfCurrentView rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound ) {
return YES;
}
currentView = currentView.superview;
}
return NO;
}
答案 10 :(得分:0)
上述所有解决方案似乎都有点复杂。我正在使用一个名为isInPopover
的变量,如果视图控制器以弹出框形式显示,我将其设置为true。在popoverControllerDidDismissPopover
或viewWillDisappear
中的视图控制器中,我将布尔值设置为false。它确实有效,而且很简单。
答案 11 :(得分:0)
由于self.popoverPresentationController
是在最近的iOS版本中懒散创建的,因此应该检查self.popoverPresentationController.presentingViewController
的nil-ness,如果不是n,这将意味着self
当前在弹出窗口中显示。
答案 12 :(得分:0)
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
}