UIPopoverController 使用总结

先看他的继承关系,UIPopoverController是直接继承自NSObject,它和UIViewController没有关系.那它是怎么实现弹出在全部View之上的,我猜想是利用了keywindow,把这个View加在keywindow里面,我作了个试验,通常咱们会在AppDelegate的didFinishLaunchingWithOptions中来初始化咱们的window,把应用的第一个viewcontroller加到window中去,并在最后调用window的makekeyandvisible方法。因而我尝试在window实例调用makekeyandvisible方法的以前弹出一个UIPopoverController,因而获得了下面的错误:数组

***Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:'-[UIPopoverController presentPopoverFromRect:inView:permittedArrowDirections:animated:]: Popovers cannot be presented from a view which does not have a window.'app

 

因此我猜UIPopoverController就是把你提供的Viewcontroller包起来加一个arrow框和背景,加到keywindow中去。另外若是你在显示地时候传入的BarButtonItem为nil,也会报这个错误,但实际上和window无关。ide

使用注意:优化

1、.UIPopoverController该控制器的内容必须由一个控制器提供;提供方式有3个:ui

一、atom

- (id)initWithContentViewController:(UIViewController *)viewControllerspa

//很简单的初始化方法,把你要展现的Viewcontroller传给它。代理

二、继承

-(void)setContentViewController:(UIViewController*)viewController animated:(BOOL)animatedip

//能够在UIPopoverController还在显示的时候动态地更换ContentViewController。

三、

@property (nonatomic, retain) UIViewController *contentViewController

 

2、设置内容大小:

/* This property allows direction manipulation of the content size of the popover. Changing the property directly is equivalent to animated=YES. The content size is limited to a minimum width of 320 and a maximum width of 600. */ @property (nonatomic) CGSize popoverContentSize; - (void)setPopoverContentSize:(CGSize)size animated:(BOOL)animated;

 

/* contentSizeForViewInPopover allows you to set the size of the content from within the view controller. This property is read/write, and you should generally not override it. */ @property (nonatomic,readwrite) CGSize contentSizeForViewInPopover NS_AVAILABLE_IOS(3_2);

 

三.设置箭头方向:

@property (nonatomic, readonly) UIPopoverArrowDirection popoverArrowDirection

 

typedef NS_OPTIONS(NSUInteger, UIPopoverArrowDirection) {

    UIPopoverArrowDirectionUp = 1UL << 0,

    UIPopoverArrowDirectionDown = 1UL << 1,

    UIPopoverArrowDirectionLeft = 1UL << 2,

    UIPopoverArrowDirectionRight = 1UL << 3,

    UIPopoverArrowDirectionAny = UIPopoverArrowDirectionUp | UIPopoverArrowDirectionDown | UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionRight,

    UIPopoverArrowDirectionUnknown = NSUIntegerMax

};

 

4、

一、若是从一个导航按钮处呈现,使用:

presentPopoverFromBarButtonItem:permittedArrowDirections:animated:;

这种方式弹出的popVC接近于模态, 但不彻底是模态, 由于NavigationBar上的全部按钮都高于这个popVC层, 也就是说NavigationBar上的按钮能够继续响应用户的操做,而无论当前是否有从BarButtonItem弹出的popVC。

这样就有可能引起一些问题, 如, 咱们再次点击这个BarButtonItem时, 则又会执行一次弹出操做, 实际上界面上将会有两个popOver, 更明显的问题是, 若是咱们点navigationBar上的返回按钮,把当前这个界面pop出去, 则会由于当前还有展现的popVC而使当前界面崩溃。

通常实现:

- (IBAction)languageButtonTapped {

    if (self.languagePopoverController == nil) {

        BIDLanguageListController *languageListController =

        [[BIDLanguageListController alloc] init];

        languageListController.detailViewController = self;

        UIPopoverController *poc = [[UIPopoverController alloc]

                                    initWithContentViewController:languageListController];

        [poc presentPopoverFromBarButtonItem:languageButton

                    permittedArrowDirections:UIPopoverArrowDirectionAny

                                    animated:YES];

        self.languagePopoverController = poc;

    } else {

        if (languagePopoverController != nil) {

            [languagePopoverController dismissPopoverAnimated:YES];

            self.languagePopoverController = nil;

        }

    }

}


二、若是要从一个视图出呈现,使用:

presentPopoverFromRect:inView:permittedArrowDirections:animated:

这个方法须要传入一个CGRect和一个View,而只有这个CGRect的值是相对于这个View的,这个Arrow才能指到正确的位置。我猜想它是在视图树中向上搜索把它转化为在keywindow中的值再显示。举个例子,若是你要箭头指向被点击的这个button,

那么一种方法是:

[xxx presentPopoverFromRect:button.bounds inView:button permittedArrowDirections:xx animated:YES];

一种方法是转换为他的父视图中的CGRect:

[xxx presentPopoverFromRect:button.frame inView:button.superview permittedArrowDirections:xx animated:YES];

 // inView的中心点是用来画箭头的,若是中心点若是出了屏幕,系统会优化到窗口边缘

//inView是个CGRectMake(x0, y0, x1, y1),若是你想绝对定位的话,能够把x1,y1设置为0,x0,y0就是箭头的位置。

这种方式弹出的popVC就是绝对的模态了, 不把这个popVC消隐, 其它任何地方, 包括NavigtionBar都获得不交互。

注意:若是设备旋转之后,位置定位错误须要在父视图控制器的下面方法里面从新定位:

didRotateFromInterfaceOrientation:(在这个方法体里面从新设置rect)

而后再次调用:

- (void)presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated

 

5、UIPopoverController的外观

经过popoverBackgroundViewClass属性和popoverLayoutMargins,你就能够本身定制Popover的外观了,popoverLayoutMargins是指你的popover相对于整个window上下左右的margin,当你设置的值大于它目前的值的时候,它才会调整(也就是让它本身更小的margin才会被实现).另外经过subclass UIPopoverBackgroundView,并把该class指定给popoverBackgroundViewClass属性,你就能够随意改变他的外观了。

 

6、UIPopoverController防止点击区域外消失

UIPopoverController的默认行为是,当你点击UIPopoverController之外的区域时,它会消失,改变这种行为就要利用属性passthroughViews.它的意思是,UIPopoverController点击在它的区域外,若是点到了passthroughViews中的View的时候,是不会消失的。我写了demo试了一下,passthroughView中被点击的View以及其SubView都不会让UIPopoverController消失。

通常点击区域外消失实现代理来处理后续动做:

- (void)popoverControllerDidDismissPopover:(UIPopoverController*)popoverController{

      if (popover) {

          [popover dismissPopoverAnimated:YES];

          [popover release];

          popover=nil;

          if (popoverContent != nil) {

              [popoverContent release];

              popoverContent = nil;

          }

      }

  }

 

7、UIPopoverController的内存管理

根据目前我使用的状况来看,我经常使用的使用方式是在属性中声明一个 retain 的 UIPopoverController,而后在建立的时候指向建立的临时变量,而后释放临时变量.我尚未发现更方便的内存管理的方法,UIPopoverController和UIActionSheet有点不同,你必须本身来retain这个UIPopoverController,若是在UIPopoverController尚未dismiss的时候你就release掉了,就会出错。固然,你能够把UIPopoverController的delegate设为self,而后在popoverControllerDidDismissPopover中释放他,但我感受这样还不如采用属性更方便,由于你无法代码控制popover的消失了,总得维护一个引用,固然,象我这种方法得话,你不少时候是在延迟释放这个popOver了。

通常来讲,你能够常用这样得代码:

[self.pop dismissPopoverAnimate:xx];

self.pop=nil;

由于给nil发送一个dismissxx是没有问题的,而后再释放,这样能够保证内存不混出错。固然,若是实在不放心,能够老是在前面加一个if(!=nil)的判断。

 

7、

多个UIPopoverController的切换问题

状况描述:多个button控制对应的UIPopoverController,当一个UIpopverController_A打开的时候,点击button_B去打开另一个UIPopverContrller_B,每次都须要点击两下才能打开,(个人理解)第一次只是关闭UIpopverController_A,第二次才是打开UIPopverContrller_B。

解决方法:

UIPopoverController * poper...

UIButton * BtnA...

NSArray *array=[NSArray arrayWithObjects:BtnA,BtnB,BtnC,BtnD,BtnE,BtnF,BtnG,BtnH];

poper.passthroughViews=array;

设置passthroughViews为这个数组就能够了

相关文章
相关标签/搜索