(一〇六)iPad开发之UIPopoverController的使用

很多App里都有一种点击显示的悬浮气泡菜单,例如下图:

在iPad上可以使用UIPopoverController实现这个功能,popoverController继承自NSObject而不是UIView,这是因为它本身并不能显示,popoverController的显示内容取决于成员属性contentViewController,并且该属性必须在初始化时被传入,否则会崩溃

popover的尺寸应该由contentView决定,而不应该在外部设置,下面的代码实现了一个contentView,用于popover显示一个类似上图的菜单。

使用self.preferredContentSize属性来决定popover的尺寸。

//
//  TableViewController.m
//  iPad初步
//
//  Created by 11 on 8/4/15.
//  Copyright (c) 2015 soulghost. All rights reserved.
//

#import "TableViewController.h"

@interface TableViewController ()

@property (nonatomic, strong) NSMutableArray *menuList;

@end

@implementation TableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = @"菜单";
    
    CGFloat width = self.menuList.count * 44;
    // 过期的方法self.contentSizeForViewInPopover需要计算导航控制器的标题宽度44,在iOS8不可用。
    self.preferredContentSize = CGSizeMake(self.view.bounds.size.width * 0.5, width);
    
}

- (NSMutableArray *)menuList{
    
    if (_menuList == nil) {
        _menuList = [NSMutableArray arrayWithObjects:@"文件",@"编辑",@"设置",@"返回",nil];
    }
    
    return _menuList;
    
}

#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    return self.menuList.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    static NSString  *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    
    // 在这里设置cell数据
    cell.textLabel.text = self.menuList[indexPath.row];
    
    return cell;
    
}



@end
创建popoverView后,在iOS7如果不主动对其进行强引用会使得popoverView在显示时被释放,因此需要指定一个成员属性防止其释放;在iOS8和以后,即使不强引用也可以,但是为了适配,应该指定这个成员属性。
下面的代码演示了一个popoverView的创建:

- (IBAction)menuClick:(id)sender {
    
    // 创建Popover的显示内容(View)。
    TableViewController *tvc = [[TableViewController alloc] init];
    UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:tvc];
    
    // 创建Popover,确定内容,确定尺寸,指定显示位置。
    UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:nvc];
    _popoverVc = popover;
    _popoverVc.delegate = self;
    // popover的尺寸由其内的视图控制器决定。
    
    // 设置穿透蒙板的Views
    _popoverVc.passthroughViews = @[_segmentBtn];
    
    // 要指向谁,rect传入谁的bounds
    // inView是Rect的参考系
    [popover presentPopoverFromRect:_menuBtn.bounds inView:_menuBtn permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    
}
注意其中的passthroughViews数组是指的能够穿过popoverView蒙板的views,因为popoverView显示时会有一个遮盖阻止用户与其他控件交互,在这个数组中的views可以穿过蒙板进行交互。

present方法传入的inView是popoverView位置的参考系,rect是显示的位置,一般有两种传递方法:①rect传入bounds而参考系为当前控件,②rect传入frame而参考系为父控件。


popoverView还有代理方法,用于阻止其dismiss或者监听销毁。

- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController{
    
    return YES;// 返回NO不能销毁
    
}
// 只有系统自己销毁才会调用,主动dismiss不会调用。
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController{
    
    NSLog(@"已经销毁");
    
}
第一个代理方法返回NO时不能销毁,利用这个方法可以做一些判断来决定能否销毁。

第二个代理方法在系统销毁popoverView时调用,如果自己dismiss是不会调用的

原文地址:https://www.cnblogs.com/aiwz/p/6154081.html