前言
在iPad开发中,有一个控件叫做UIPopoverController(只能在iPad上用,不能在iPhone中用),它的作用是在点击按钮上显示一个弹出框。下面我们来一起看看如何在iPhone上实现UIPopoverController的效果。
1、iPad上UIPopoverController的用法
- iPad上使用UIPopoverController
- (void)btnTapAction:(UIButton *)btn
{
YJViewController *yjViewController = [[YJViewController alloc] init];
YJViewController.title = @"关于我们";
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:YJViewController];
UIPopoverController* abourtPopoverController = [[UIPopoverController alloc] initWithContentViewController:navigation];
//弹出窗口大小
abourtPopoverController.popoverContentSize = CGSizeMake(320,480);
//弹出关于界面
[abourtPopoverController presentPopoverFromRect:btn.frame //中心点是用来画箭头的,如果中心点如果出了屏幕,系统会优化到窗口边缘
inView:btn.superview
permittedArrowDirections:UIPopoverArrowDirectionDown //箭头方向
animated:YES];
}
2、实现iPhone上的弹出框-----YJPopoverController
- 先看初始化接口
/**
*
* @param contentViewController 内容视图
* @param popoverContentSize 内容视图大小
*
*/
- (instancetype)initWithContentViewController:(UIViewController *)contentViewController popoverContentSize:(CGSize)popoverContentSize;
- 初始化之后就来调用该类,箭头支持四个方向
/**
*
* @param fromRect 以此rect来决定弹出框位置
* @param inView fromRect参数是以此view为参考
* @param permitterArrowDirection 箭头方向
* @param animated 是否有动画
*/
- (void)presentPopoverFromRect:(CGRect)fromRect inView:(UIView *)inView permitterArrowDirections:(YJPopoverArrowDirection)permitterArrowDirection animated:(BOOL)animated;
//箭头类型
typedef NS_ENUM(NSUInteger, YJPopoverArrowDirection) {
YJPopoverArrowDirection_up, //箭头向上
YJPopoverArrowDirection_left, //箭头向左
YJPopoverArrowDirection_down, //箭头向下
YJPopoverArrowDirection_right //箭头向右
};
- 完整的调用代码
- (IBAction)btnPopDownTapAction:(UIButton *)btn
{
YJPopoverContentController *contentController= [[YJPopoverContentController alloc] init];
YJPopoverController *popController = [[YJPopoverController alloc] initWithContentViewController:contentController popoverContentSize:CGSizeMake(150, 35 * 3 + 10)];
[popController presentPopoverFromRect:btn.frame inView:btn.superview permitterArrowDirections:YJPopoverArrowDirection_down animated:YES];
}
3、YJPopoverController实现原理
本框架由两个类组成,YJPopoverController和YJPopoverView。YJPopoverView用来画背景框(包括箭头),YJPopoverController用来显示和管理YJPopoverView和内容视图。
YJPopoverView继承自UIView,根据箭头方向画背景框
- (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] setFill];
CGContextRef context = UIGraphicsGetCurrentContext();
switch (self.arrowDirection) {
case YJPopoverArrowDirection_up:
{
CGContextMoveToPoint(context, self.arrowLocation, CGRectGetMinY(rect));
CGContextAddLineToPoint(context, self.arrowLocation - kPopoverViewArrowHeight, CGRectGetMinY(rect) + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect) + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect) + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, self.arrowLocation + kPopoverViewArrowHeight, CGRectGetMinY(rect) + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, self.arrowLocation, CGRectGetMinY(rect));
}
break;
case YJPopoverArrowDirection_left:
{
CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect) - kPopoverViewArrowHeight, CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect) - kPopoverViewArrowHeight, self.arrowLocation + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), self.arrowLocation);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect) - kPopoverViewArrowHeight, self.arrowLocation - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect) - kPopoverViewArrowHeight, CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
}
break;
case YJPopoverArrowDirection_down:
{
CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect) - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, self.arrowLocation - kPopoverViewArrowHeight, CGRectGetMaxY(rect) - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, self.arrowLocation, CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, self.arrowLocation + kPopoverViewArrowHeight, CGRectGetMaxY(rect) - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect) - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
}
break;
case YJPopoverArrowDirection_right:
{
CGContextMoveToPoint(context, CGRectGetMinX(rect) + kPopoverViewArrowHeight, CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect) + kPopoverViewArrowHeight, self.arrowLocation - kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMinX(rect), self.arrowLocation);
CGContextAddLineToPoint(context, CGRectGetMinX(rect) + kPopoverViewArrowHeight, self.arrowLocation + kPopoverViewArrowHeight);
CGContextAddLineToPoint(context, CGRectGetMinX(rect) + kPopoverViewArrowHeight, CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMinX(rect) + kPopoverViewArrowHeight, CGRectGetMinY(rect));
}
break;
default:
break;
}
CGContextDrawPath(context, kCGPathFillStroke);
}
- YJPopoverController用来显示YJPopoverView和内容视图,同时对弹出框超过屏幕边缘的时候做一些纠正处理。
- (void)presentPopoverFromRect:(CGRect)fromRect inView:(UIView *)inView permitterArrowDirections:(YJPopoverArrowDirection)permitterArrowDirection animated:(BOOL)animated
{
self.popoverView.arrowDirection = permitterArrowDirection;
CGRect contentRect = [inView convertRect:fromRect toView:kYJCurrentWindow];
switch (permitterArrowDirection) {
case YJPopoverArrowDirection_up:
{
self.contentViewRect = CGRectMake(0, kPopoverViewArrowHeight, self.popoverContentSize.width, self.popoverContentSize.height);
CGFloat viewLeft;
CGFloat viewRight;
//点击视图位于屏幕左边时, 判断弹出视图是否超出屏幕左边缘,如果超出就将弹出视图整个右移;
//点击视图位于屏幕右边时, 判断弹出视图是否超出屏幕右边缘,如果超出就将弹出视图整个左移;
if (CGRectGetMidX(contentRect) <= CGRectGetMidX(kYJCurrentWindow.bounds)) {
viewLeft = CGRectGetMidX(contentRect) - self.popoverContentSize.width / 2;
if (viewLeft < 0) {
viewLeft = kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetMidX(contentRect) - viewLeft;
self.view.frame = CGRectMake(viewLeft, CGRectGetMaxY(contentRect) + kPopoverViewMaginToBtn, self.popoverContentSize.width, self.popoverContentSize.height);
}
else {
viewRight = CGRectGetMidX(contentRect) + self.popoverContentSize.width / 2;
if (viewRight > kYJScreenWidth) {
viewRight = kYJScreenWidth - kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetWidth(self.popoverView.bounds) - (viewRight - CGRectGetMidX(contentRect));
self.view.frame = CGRectMake(viewRight - self.popoverContentSize.width, CGRectGetMaxY(contentRect) + kPopoverViewMaginToBtn, self.popoverContentSize.width, self.popoverContentSize.height);
}
}
break;
case YJPopoverArrowDirection_left:
{
self.contentViewRect = CGRectMake(0, 0, self.popoverContentSize.width - kPopoverViewArrowHeight, self.popoverContentSize.height);
CGFloat viewTop;
CGFloat viewBottom;
//点击视图位于屏幕上方时, 判断弹出视图是否超出屏幕上边缘,如果超出就将弹出视图整个下移;
//点击视图位于屏幕下方时, 判断弹出视图是否超出屏幕下边缘,如果超出就将弹出视图整个上移;
if (CGRectGetMidY(contentRect) <= CGRectGetMidY(kYJCurrentWindow.bounds)) {
viewTop = CGRectGetMidY(contentRect) - self.popoverContentSize.height / 2;
if (viewTop < 0) {
viewTop = kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetMidY(contentRect) - viewTop;
self.view.frame = CGRectMake(CGRectGetMinX(contentRect) - kPopoverViewMaginToBtn - self.popoverContentSize.width, viewTop, self.popoverContentSize.width, self.popoverContentSize.height);
}
else {
viewBottom = CGRectGetMidY(contentRect) + self.popoverContentSize.height / 2;
if (viewBottom > kYJScreenHeight) {
viewBottom = kYJScreenHeight - kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetHeight(self.popoverView.bounds) - (viewBottom - CGRectGetMidY(contentRect));
self.view.frame = CGRectMake(CGRectGetMinX(contentRect) - kPopoverViewMaginToBtn - self.popoverContentSize.width, viewBottom - self.popoverContentSize.height, self.popoverContentSize.width, self.popoverContentSize.height);
}
}
break;
case YJPopoverArrowDirection_down:
{
self.contentViewRect = CGRectMake(0, 0, self.popoverContentSize.width, self.popoverContentSize.height - kPopoverViewArrowHeight);
CGFloat viewLeft, viewRight;
//点击视图位于屏幕左边时, 判断弹出视图是否超出屏幕左边缘,如果超出就将弹出视图整个右移;
//点击视图位于屏幕右边时, 判断弹出视图是否超出屏幕右边缘,如果超出就将弹出视图整个左移;
if (CGRectGetMidX(contentRect) <= CGRectGetMidX(kYJCurrentWindow.bounds)) {
viewLeft = CGRectGetMidX(contentRect) - self.popoverContentSize.width / 2;
if (viewLeft < 0) {
viewLeft = kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetMidX(contentRect) - viewLeft;
self.view.frame = CGRectMake(viewLeft, CGRectGetMinY(contentRect) - kPopoverViewMaginToBtn - self.popoverContentSize.height, self.popoverContentSize.width, self.popoverContentSize.height);
}
else {
viewRight = CGRectGetMidX(contentRect) + self.popoverContentSize.width / 2;
if (viewRight > kYJScreenWidth) {
viewRight = kYJScreenWidth - kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetWidth(self.popoverView.bounds) - (viewRight - CGRectGetMidX(contentRect));
self.view.frame = CGRectMake(viewRight - self.popoverContentSize.width, CGRectGetMinY(contentRect) - kPopoverViewMaginToBtn - self.popoverContentSize.height, self.popoverContentSize.width, self.popoverContentSize.height);
}
}
break;
case YJPopoverArrowDirection_right:
{
self.contentViewRect = CGRectMake(kPopoverViewArrowHeight, 0, self.popoverContentSize.width - kPopoverViewArrowHeight, self.popoverContentSize.height);
CGFloat viewTop, viewBottom;
//点击视图位于屏幕上方时, 判断弹出视图是否超出屏幕上边缘,如果超出就将弹出视图整个下移;
//点击视图位于屏幕下方时, 判断弹出视图是否超出屏幕下边缘,如果超出就将弹出视图整个上移;
if (CGRectGetMidY(contentRect) <= CGRectGetMidY(kYJCurrentWindow.bounds)) {
viewTop = CGRectGetMidY(contentRect) - self.popoverContentSize.height / 2;
if (viewTop < 0) {
viewTop = kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetMidY(contentRect) - viewTop;
self.view.frame = CGRectMake(CGRectGetMaxX(contentRect) + kPopoverViewMaginToBtn, viewTop, self.popoverContentSize.width, self.popoverContentSize.height);
}
else {
viewBottom = CGRectGetMidY(contentRect) + self.popoverContentSize.height / 2;
if (viewBottom > kYJScreenHeight) {
viewBottom = kYJScreenHeight - kPopoverViewMaginToScreen;
}
self.popoverView.arrowLocation = CGRectGetHeight(self.popoverView.bounds) - (viewBottom - CGRectGetMidY(contentRect));
self.view.frame = CGRectMake(CGRectGetMaxX(contentRect) + kPopoverViewMaginToBtn, viewBottom - self.popoverContentSize.height, self.popoverContentSize.width, self.popoverContentSize.height);
}
}
break;
default:
break;
}
[kYJPopViewManager showPopView:self.view disMissBlock:^{
[self.contentViewController willMoveToParentViewController:nil];
[self.contentViewController.view removeFromSuperview];
[self.contentViewController removeFromParentViewController];
}];
}