在做项目的时候,经常会遇到弹出框,如果使用一些第三方的感觉太臃肿了。使用系统的UIPopoverController,我们知道这个以前是只能在iPad上用。

现在在iOS8以后在iPhone上有了,它使用全新的方式来显示。
所以我们还是用新的方法来使用系统自带的PopoverView以及一些效果的定制。

最终效果:
效果图

我们找到UIPopoverController,可以看到在头文件中写到

NS_CLASS_DEPRECATED_IOS(3_2, 9_0, "UIPopoverController is deprecated. Popovers are now implemented as UIViewController presentations. Use a modal presentation style of UIModalPresentationPopover and UIPopoverPresentationController.")

告诉我们这个类已经从iOS9废弃使用了,现在使用需要使用模态推送来推出。

弹出窗口

弹出框最常用的就像手Q,微信那样的,弹出的是一个选项卡类型的,我们使用TableView来显示:
新建一个类继承UITableViewController

@interface TPPopoverView : UITableViewController

在这个类中写好显示出我们内容的东西,再写个代理来回调我们点击了哪一项。

好,写好以后初始化,先设置模态推送的样式为UIModalPresentationPopover,再设置大小

TPPopoverView *contentController = [[TPPopoverView alloc] init];
contentController.modalPresentationStyle = UIModalPresentationPopover;
contentController.preferredContentSize = CGSizeMake(120, 45 * [dataList count]);

设置好以后使用系统的Category,@interface UIViewController (UIAdaptivePresentations)中的popoverPresentationController属性来设置弹出以后的具体样式

UIPopoverPresentationController *popVC = contentController.popoverPresentationController;
popVC.delegate = self;
popVC.barButtonItem = sender;
[self presentViewController:contentController animated:YES completion:nil];

在这里去设置他的代理和从哪个位置弹出,这里是从导航条上的按钮弹出的,我们也可以设置其他地方退出,只需要设置

//    popVC.popoverLayoutMargins = UIEdgeInsetsMake(15, 0, 0, 15);
//    popVC.sourceView = self.view;
//    popVC.sourceRect = CGRectMake(SCREEN_WIDTH - 35, 0, 0, 0);

设置sourceView = self.view 就是从self.view弹出,你也可以设置成其他的view,而sourceRect就能设置具体的位置了。arrowDirection设置箭头的方向,使用默认的就行了

都写好了以后直接present

[self presentViewController:contentController animated:YES completion:nil];
/*注意这里是`contentController`而不是`popVC`*/

这样弹出以后发现是全屏的,原来还要写UIPopoverPresentationController的代理方法adaptivePresentationStyleForPresentationController:

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

这样就弹出我们设置好大小的PopoverView了。

定制样式

上面的步骤只是把PopoverView弹出来,但发现箭头是圆角的,后面的阴影也比较重,我们去定制一下他的样式。
新建一个类继承UIPopoverBackgroundView

@interface TPPopoverBackgroundView : UIPopoverBackgroundView

在初始化方法initWithFrame:

//TODO: update with border image view
UIImageView *arrowImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
self.arrowImageView = arrowImageView;
self.layer.shadowColor = [UIColor lightGrayColor].CGColor; 
[self addSubview:self.arrowImageView];

添加一个UIImageView来显示箭头,把阴影调淡一点。

还需要重写

+ (CGFloat)arrowBase {
    return kArrowBase;
}

+ (CGFloat)arrowHeight {
    return kArrowHeight;
}

+ (UIEdgeInsets)contentViewInsets {
    return UIEdgeInsetsMake(kOffset, kBorderInset, kBorderInset, kBorderInset);
}

+ (BOOL)wantsDefaultContentAppearance {
    return NO;
}

这几个方法,来设置箭头的大小,内容的边距等
最后在layoutSubviews中来画箭头和设置箭头的位置

- (void)layoutSubviews {
    [super layoutSubviews];
    CGSize arrowSize = CGSizeMake([[self class] arrowBase], [[self class] arrowHeight]);
    self.arrowImageView.image = [self drawArrowImage:arrowSize];
    self.arrowImageView.frame = CGRectMake(((self.bounds.size.width - arrowSize.width) - 8), kOffset, arrowSize.width, arrowSize.height);
}

画三角形的代码:

- (UIImage *)drawArrowImage:(CGSize)size {
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [[UIColor clearColor] setFill];
    CGContextFillRect(ctx, CGRectMake(0.0f, 0.0f, size.width, size.height));

    CGMutablePathRef arrowPath = CGPathCreateMutable();
    CGPathMoveToPoint(arrowPath, NULL, (size.width/2.0f), 0.0f); //Top Center
    CGPathAddLineToPoint(arrowPath, NULL, size.width, size.height); //Bottom Right
    CGPathAddLineToPoint(arrowPath, NULL, 0.0f, size.height); //Bottom Right
    CGPathCloseSubpath(arrowPath);
    CGContextAddPath(ctx, arrowPath);
    CGPathRelease(arrowPath);

    UIColor *fillColor = [UIColor whiteColor];
    CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
    CGContextDrawPath(ctx, kCGPathFill);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

使用:
在popoverPresentationController设置样式的时候加上

UIPopoverPresentationController *popVC = contentController.popoverPresentationController;
popVC.delegate = self;
popVC.barButtonItem = sender;
popVC.popoverBackgroundViewClass = [TPPopoverBackgroundView class];
[self presentViewController:contentController animated:YES completion:nil];

至此就大功告成了~

最后附上源码:https://github.com/tonlen/TPPopoverView

TAG:ios, popover