iOS 弹出框总结

代码下载地址一
代码下载地址二

前言

在iOS应用程序中,我们经常看到各种各样的弹出框,比如地理信息、相册、相机、权限的弹出框,图片来源选择弹出框,信息提示弹出框,下拉弹出框等。这篇文章主要总结UIPopoverController、UIPopoverPresentationController、UIAlertView、UIActionSheet、UIAlertController的使用。

UIPopoverController

UIPopoverController是ipad上特有的界面元素,用户可以在其边界外单击来关闭它,在iOS9中被弃用,只能使用于iPad,在iPhone中奔溃!它需要一个UIViewController作为其内容,我们应该还会考虑弹出窗口的大小与显示的位置。可以提供一个CGRect指定弹出窗口的参考位置。用popoverContentSize这个属性来设置弹出框的大小。可以通过- (void)presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated这个方法来显示窗口,UIPopoverArrowDirection表示箭头的方向

Simulator Screen Shot 2016年10月24日 下午5.17.17.png
//新建一个内容控制器
InfoViewController *infoViewController = [[InfoViewController alloc] init];
UIPopoverController *popViewController = [[UIPopoverController alloc] initWithContentViewController:infoViewController];
//设置弹出窗口大小,如果屏幕画不下,会挤小的。这个值默认是320x1100
popViewController.popoverContentSize = CGSizeMake(200, 100);
//设置弹出窗口的参考位置
CGRect rect = CGRectMake(0, 0, 0, 0);
NSIndexPath *indexPath = [weakSelf.tableView indexPathForSelectedRow];
UITableViewCell *cell = [weakSelf.tableView cellForRowAtIndexPath:indexPath];
[popViewController presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];

另一种显示的方法是- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated,这种方式依附于导航栏的UIBarButtonItem上。

Simulator Screen Shot 2016年10月24日 下午5.17.20.png
 //新建一个内容控制器
InfoViewController *infoViewController = [[InfoViewController alloc] init];
//用于任何容器布局子控制器,弹出窗口的原始大小来自视图控制器的此属性,如果设置了此属性那么UIPopoverController的popoverContentSize属性会失效。
infoViewController.preferredContentSize = CGSizeMake(200, 200);
                                                            
UIPopoverController *popViewController = [[UIPopoverController alloc] initWithContentViewController:infoViewController];
//设置弹出窗口大小,如果屏幕画不下,会挤小的。这个值默认是320x1100
popViewController.popoverContentSize = CGSizeMake(200, 100);
 /*
UIPopoverArrowDirection:箭头方向
*/
[popViewController presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

需要注意的是如果设置了弹出控制器的preperredContentSize属性那么UIPopoverController的popoverContentSize属性会失效,另外UIPopoverController有如下几个代理方法:
用来决定用户点击了蒙版后,popoverController是否可以dismiss,返回YES代表可以,返回NO代表不可以
-(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
UIPopoverController消失的时候调用
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
UIPopoverController的位置改变的时候调用(如竖屏变横屏)
-(void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView * __nonnull * __nonnull)view

UIPopoverController还有两个比较有用的属性,isPopoverVisible属性是只读的,用于判断是否弹出控制器。还有一个passthroughViews属性,默认情况下,UIPopoverController弹出后不允许用户交互任何视图弹出框外面。passthroughViews属性允许指定的数组UIView的实例允许用户交互。

Simulator Screen Shot 2016年10月24日 下午5.18.03.png
 //判断是否弹出控制器
if (weakSelf.popoverController.isPopoverVisible) {
       [weakSelf.popoverController dismissPopoverAnimated:YES];
}
 else
{
        //设置弹出窗口大小,如果屏幕画不下,会挤小的。这个值默认是320x1100
        //popViewController.popoverContentSize = CGSizeMake(200, 100);
        //设置弹出窗口的参考位置
        CGRect rect = CGRectMake(0, 0, 0, 0);
        NSIndexPath *indexPath = [weakSelf.tableView indexPathForSelectedRow];
        UITableViewCell *cell = [weakSelf.tableView cellForRowAtIndexPath:indexPath];
        //设置可交互的预留控件
        popViewController.passthroughViews = @[cell];
        /*
        UIPopoverArrowDirection:箭头方向
        */
        [popViewController presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}

UIPopoverPresentationController

UIPopoverPresentationController适用于iPhone和ipad,不过在iPhone上展现形式就为普通的模态视图,而不是弹窗的形式。UIPopoverPresentationController是UIViewController实例的属性,不需要创建,获取就可以啦。它同样需要一个UIViewController作为其内容,通过设置UIViewController实例的modalPresentationStyle的这个属性为UIModalPresentationPopover来使用UIPopoverPresentationController,还有就是它是通过- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion 方法来显示的。其他使用方式和UIPopoverController基本差不多,列如:
sourceView属性设置所依附的控件、
sourceRect属性设置弹出窗口对所依附的控件的参考位置、
permittedArrowDirections属性设置箭头方向、
passthroughViews属性设置可交互的预留控件

Simulator Screen Shot 2016年10月27日 下午5.50.48.png
    //新建一个内容控制器
    InfoViewController *infoViewController = [InfoViewController infoViewController];

    //用于任何容器布局子控制器,弹出窗口的原始大小来自视图控制器的此属性,如果设置了此属性那么UIPopoverController的popoverContentSize属性会失效。
    infoViewController.preferredContentSize = CGSizeMake(200, 200);
    //设置模态视图弹出的样式
    [infoViewController setModalPresentationStyle:UIModalPresentationPopover];

    //取出点击的cell
    NSIndexPath *indexPath = [weakSelf.tableView indexPathForSelectedRow];
    UITableViewCell *cell = [weakSelf.tableView cellForRowAtIndexPath:indexPath];

    //UIPopoverPresentationController是UIViewController实例的属性,不需要创建,获取就可以啦
    UIPopoverPresentationController *presentationCtr = infoViewController.popoverPresentationController;
    //设置弹出窗口所依附的控件
    presentationCtr.sourceView = cell;
    //设置弹出窗口对所依附的控件的参考位置
    presentationCtr.sourceRect = CGRectMake(10, 10, 20, 20);
    //设置箭头方向
    presentationCtr.permittedArrowDirections = UIPopoverArrowDirectionLeft;
    //设置代理
    presentationCtr.delegate = weakSelf;

    //弹出模态视图
    [weakSelf presentViewController:infoViewController animated:YES completion:nil];
Simulator Screen Shot 2016年10月27日 下午5.50.50.png
      //新建一个内容控制器
      InfoViewController *infoViewController = [InfoViewController infoViewController];
      
      //用于任何容器布局子控制器,弹出窗口的原始大小来自视图控制器的此属性,如果设置了此属性那么UIPopoverController的popoverContentSize属性会失效。
      infoViewController.preferredContentSize = CGSizeMake(200, 200);
      //设置模态视图弹出的样式
      [infoViewController setModalPresentationStyle:UIModalPresentationPopover];
      
      //UIPopoverPresentationController是UIViewController实例的属性,不需要创建,获取就可以啦
      UIPopoverPresentationController *presentationCtr = infoViewController.popoverPresentationController;
      //设置所依附的UIBarButtonItem
      presentationCtr.barButtonItem = weakSelf.navigationItem.rightBarButtonItem;
      //设置箭头方向
      presentationCtr.permittedArrowDirections = UIPopoverArrowDirectionUp;
      //设置代理
      presentationCtr.delegate = weakSelf;
      
      //弹出模态视图
      [weakSelf presentViewController:infoViewController animated:YES completion:nil];
Simulator Screen Shot 2016年10月27日 下午5.50.55.png
      if (weakSelf.presentedViewController) {
          [weakSelf dismissViewControllerAnimated:YES completion:nil];
      }
      else
      {
          //新建一个内容控制器
          InfoViewController *infoViewController = [InfoViewController infoViewController];
          
          //用于任何容器布局子控制器,弹出窗口的原始大小来自视图控制器的此属性,如果设置了此属性那么UIPopoverController的popoverContentSize属性会失效。
          infoViewController.preferredContentSize = CGSizeMake(200, 200);
          //设置模态视图弹出的样式
          [infoViewController setModalPresentationStyle:UIModalPresentationPopover];
          
          //UIPopoverPresentationController是UIViewController实例的属性,不需要创建,获取就可以啦
          UIPopoverPresentationController *presentationCtr = infoViewController.popoverPresentationController;
          //设置所依附的UIBarButtonItem
          presentationCtr.barButtonItem = weakSelf.navigationItem.rightBarButtonItem;
          //设置箭头方向
          presentationCtr.permittedArrowDirections = UIPopoverArrowDirectionUp;
          //设置代理
          presentationCtr.delegate = weakSelf;
          
          //取出点击的cell
          NSIndexPath *indexPath = [weakSelf.tableView indexPathForSelectedRow];
          UITableViewCell *cell = [weakSelf.tableView cellForRowAtIndexPath:indexPath];
          
          //设置可交互的预留控件
          presentationCtr.passthroughViews = @[cell];
          
          //弹出模态视图
          [weakSelf presentViewController:infoViewController animated:YES completion:nil];
      }

UIPopoverPresentationControllerDelegate有如下四个方法:

将要弹出的时候调用
-(void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController
在这个方法中设置是否允许消失
-(BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
已经消失的时候调用
-(void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
用到其他UIView或者CGRect的时候调用
-(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing _Nonnull *)view

UIAlertView

UIAlertView 在iOS9中被弃用,是以弹出选择框的形式展现,在iPhone和ipad中都能适用,并且展示效果一致。它的使用十分简单:
-(instancetype)initWithTitle:(nullable NSString )title message:(nullable NSString )message delegate:(nullable id /<UIAlertViewDelegate>/)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, ... 使用这个初始化方法可以设置标题,提示信息,代理对象和操作按钮。
-(NSInteger)addButtonWithTitle:(nullable NSString *)title 这个方法添加按钮。
-(nullable UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex 这个方法获取
-(void)show 这个方法用来显示UIAlertView
numberOfButtons 这个属性获取按钮的序号
visible 这个属性是用来获知是否显示的
alertViewStyle 这个属性用来设置样式的,UIAlertView有如下4中样式:
- UIAlertViewStyleDefault 默认样式,没有熟人框
- UIAlertViewStyleSecureTextInput 有一个密码输入框
- UIAlertViewStylePlainTextInput 有一个普通文本输入框
- UIAlertViewStyleLoginAndPasswordInput 有一个普通文本输入框和一个密码输入框

Simulator Screen Shot 2016年10月28日 下午5.26.56.png
   UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"选择" message:@"请选择一个数!" delegate:weakSelf cancelButtonTitle:@"取消" otherButtonTitles:nil];
   for (int index = 0; index < 100; index++) {
       [alertView addButtonWithTitle:[NSString stringWithFormat:@"%i", index]];
   }
   [alertView show];
Simulator Screen Shot 2016年10月28日 下午5.27.01.png
   UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"登录" message:@"请输入账号和密码!" delegate:weakSelf cancelButtonTitle:@"取消" otherButtonTitles:@"登录", nil];
   [alertView setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
   UITextField * firstTextField = [alertView textFieldAtIndex:0];
   firstTextField.placeholder = @"请输入账号!";
   UITextField * secondTextField = [alertView textFieldAtIndex:1];
   secondTextField.placeholder = @"请输入密码!";
   
   [alertView show];

UIAlertView有如下几个代理方法
在点击按钮的时候触发,buttonIndex为点击的按钮序号
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
在将要显示的时候触发
-(void)willPresentAlertView:(UIAlertView *)alertView
在已经显示的时候触发
-(void)didPresentAlertView:(UIAlertView *)alertView
在将要消失的时候触发
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
在已经消失的时候触发
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
在编辑文本框后触发
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView NS_DEPRECATED_IOS(2_0, 9_0);

UIActionSheet

在iOS9中被弃用,在iPhone和ipad中都能适用,但展示效果不一致。它的使用也非常简单:
-(instancetype)initWithTitle:(nullable NSString *)title delegate:(nullable id<UIActionSheetDelegate>)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle destructiveButtonTitle:(nullable NSString *)destructiveButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, ... 这个初始化方法设置标题,代理对象,信息,取消按钮和其他按钮等
-(void)showFromToolbar:(UIToolbar *)view 从UIToolbar弹出
-(void)showFromTabBar:(UITabBar *)view 从UITabBar弹出
-(void)showFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated 从UIBarButtonItem弹出
-(void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated 从UIView弹出
-(void)showInView:(UIView *)view 在UIView上弹出
说明:使用上述弹出方法iPhone上只有一种弹出效果,ipad可以有不同的弹出效果

Simulator Screen Shot 2016年10月28日 下午5.27.22.png
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"图片来源" delegate:weakSelf cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"相机", @"相册", nil];
                                    
                                    [actionSheet showFromTabBar:weakSelf.tabBarController.tabBar];

在点击按钮的时候触发,buttonIndex为点击的按钮序号

  • (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
    在将要弹出的时候触发
  • (void)willPresentActionSheet:(UIActionSheet *)actionSheet
    在已经弹出的时候触发
  • (void)didPresentActionSheet:(UIActionSheet *)actionSheet
    在将要消失的时候触发
  • (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex
    在已经消失的时候触发
  • (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex

UIAlertController

UIAlertController 在iOS8中提供,在iPhone和ipad中都能适用,但展示效果不完全一致。它的使用也十分简单:

  • (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle 这个工厂方法,创建UIAlertController实例并设置相关属性
    UIAlertController 有两种风格:
    UIAlertControllerStyleAlert,和UIAlertView的样式一致
    UIAlertControllerStyleActionSheet,和UIActionSheet的样式一致,在ipad中是通过UIPopoverPresentationController弹出的,所以需要设置UIPopoverPresentationController的相关属性,否则会出错。
  • (void)addAction:(UIAlertAction *)action 添加UIAlertAction对象
  • (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler 添加UITextField,这能为UIAlertControllerStyleAlert这个样式时才能添加UITextField
    title 标题
    message 展示信息
    preferredStyle 弹出风格
    actions 这个只读属性为添加UIAlertAction对象数组
    textFields 这个只读属性为添加UITextField对象数组

UIAlertAction对象,就相当于按钮的包装:

  • (instancetype)actionWithTitle:(nullable NSString *)title style:(UIAlertActionStyle)style handler:(void (^ __nullable)(UIAlertAction *action))handler 这个工厂方法创建UIAlertAction对象,并初始化标题,样式,和点击操作的block
    title 标题
    style 样式
    UIAlertActionStyleDefault 默认样式
    UIAlertActionStyleCancel 取消样式
    UIAlertActionStyleDestructive 严重操作样式,为红色的
    enabled 是否可用
Simulator Screen Shot 2016年10月28日 下午5.27.34.png
      //创建UIAlertController 设置标题,信息,样式
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"登录" message:@"请输入账号密码!" preferredStyle:UIAlertControllerStyleAlert];
      
      //添加UITextField
      [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
          textField.placeholder = @"请输入账号!";
          //为UITextField添加监听事件
          [textField addTarget:weakSelf action:@selector(textFieldChane:) forControlEvents:UIControlEventEditingChanged];
      }];
      //添加UITextField
      [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
          textField.placeholder = @"请输入密码!";
          //为UITextField添加监听事件
          [textField addTarget:weakSelf action:@selector(textFieldChane:) forControlEvents:UIControlEventEditingChanged];
      }];
      
      //创建UIAlertAction对象,设置标题并添加到UIAlertController上
      UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:nil];
      [alertController addAction:cancelAction];
      UIAlertAction *loginAction = [UIAlertAction actionWithTitle:@"登录" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
          
      }];
      //设置UIAlertAction对象是否可用
      loginAction.enabled = NO;
      [alertController addAction:loginAction];
      
      //展现UIAlertController
      [weakSelf presentViewController:alertController animated:YES completion:nil];
Simulator Screen Shot 2016年10月28日 下午7.07.07.png
      //创建UIAlertController 设置标题,信息,样式
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"图片来源" message:@"请添加图片!" preferredStyle:UIAlertControllerStyleActionSheet];
      
      
      //创建UIAlertAction对象,设置标题并添加到UIAlertController上
      UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
      [alertController addAction:cancelAction];
      UIAlertAction *photpAction = [UIAlertAction actionWithTitle:@"相册" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
          
      }];
      [alertController addAction:photpAction];
      UIAlertAction *cameraAction = [UIAlertAction actionWithTitle:@"相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
          
      }];
      [alertController addAction:cameraAction];
      if (IS_IPHONE) {
      }
      else
      {
          //如果在ipad上运行需要设置UIPopoverPresentationController的相关属性
          UIPopoverPresentationController *popoverPresentCtr = alertController.popoverPresentationController;
          popoverPresentCtr.barButtonItem = weakSelf.navigationItem.rightBarButtonItem;
      }
      
      //展现UIAlertController
      [weakSelf presentViewController:alertController animated:YES completion:nil];

推荐阅读更多精彩内容