iOS SDK:自定義Popover(彈出窗口)
1.設(shè)置項(xiàng)目
Step 1
打開Xcode,選擇File > New > Project,創(chuàng)建一個(gè)新項(xiàng)目,選擇iOS Single View Application,再點(diǎn)擊Next。
Step 2
填寫一些列表格,項(xiàng)目名稱、組織/公司名稱以及公司標(biāo)識(shí)符。在設(shè)備那個(gè)下拉菜單中選擇iPad,在這一欄下邊僅選擇Automatic Reference Counting,點(diǎn)擊Next。選擇一個(gè)地點(diǎn)存放你的文件,點(diǎn)擊創(chuàng)建。
2. 添加Navigation Controller
Step 1
添加Navigation Controller,這樣就能添加一個(gè)按鈕來(lái)展示popover。點(diǎn)擊AppDelegate.m,找到 application:didFinishLaunchingWithOptions:方法。添加下述代碼來(lái)創(chuàng)建一個(gè) navigation controller,設(shè)置為root view controller。
- UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
- self.window.rootViewController = navController;
Step 2
在導(dǎo)航欄上添加一個(gè)“+”的按鈕,然后打開ViewController.m文件,在[super viewDidLoad]下邊把如下代碼添加至viewDidLoad方法中。
- UIBarButtonItem *popoverButton = [[UIBarButtonItem alloc]
- initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
- target:self
- action:@selector(showPopover:)];
- self.navigationItem.rightBarButtonItem = popoverButton;
UIBarButtonSystemItemAdd創(chuàng)建了一個(gè)“+”的按鈕,我們將要把它添加至導(dǎo)航欄的右邊,接下來(lái)我們會(huì)使用選擇器執(zhí)行showPopover:方法。
3.展示Popover
Step 1
在執(zhí)行showPopover:方法前先為popover controller添加一個(gè)屬性,打開ViewController.h文件,添加如下屬性:
- @property (nonatomic, strong) UIPopoverController *popController;
Step 2
回到ViewController.m文件,在類擴(kuò)展中聲明showPopover:方法,如下:
- @interface ViewController ()
- - (void)showPopover:(id)sender;
- @end
Step 3
在@implementation下添加如下代碼來(lái)定義這個(gè)方法:
- - (void)showPopover:(id)sender
- {
- if (self.popController.popoverVisible) {
- [self.popController dismissPopoverAnimated:YES];
- return;
- }
- UIViewController *contentViewController = [[UIViewController alloc] init];
- contentViewController.view.backgroundColor = [UIColor yellowColor];
- UIPopoverController *popController = [[UIPopoverController alloc] initWithContentViewController:contentViewController];
- popController.popoverContentSize = CGSizeMake(300.0f, 600.0f);
- self.popController = popController;
- [self.popController presentPopoverFromBarButtonItem:sender
- permittedArrowDirections:UIPopoverArrowDirectionUp
- animated:YES];
- }
首先檢查下popover能否展示在屏幕上。如果popover是可見的,那么會(huì)將popover隱藏起來(lái),然后從該方法中直接return。如果 popover不可見,那么我們可以創(chuàng)建一個(gè)view controller,讓它展示在popover中。然后創(chuàng)建 popover controller,并設(shè)置大小。
4. 測(cè)試標(biāo)準(zhǔn)的Popover
我們已經(jīng)創(chuàng)建一個(gè)標(biāo)準(zhǔn)的Popover,創(chuàng)建運(yùn)行你的項(xiàng)目,點(diǎn)擊“+”按鈕來(lái)展現(xiàn)一個(gè)基本的Popover。
5. 子類化UIPopoverBackgroundView
Step 1
為了自定義popover,我們需要子類化UIPopoverBackgroundView。點(diǎn)擊 File > New > File, 選擇iOS Cocoa Touch Objective-C Class, 點(diǎn)擊Next.
Step 2
給class這一欄填上PopoverBackgroundView,從Subclass of下拉菜單中選擇UIPopoverBackgroundView。
Step 3
這里有兩個(gè)UIPopoverBackgroundView屬性需要被覆蓋,添加如下代碼來(lái)定義arrow的方向和位移。
- @synthesize arrowDirection = _arrowDirection;
- @synthesize arrowOffset = _arrowOffset;
Step 4
這里有3個(gè)類方法需要覆蓋,我們使用這個(gè)方法來(lái)定義一些值。
- #define kArrowBase 30.0f
- #define kArrowHeight 20.0f
- #define kBorderInset 8.0f
Step 5
添加如下代碼覆蓋arrowBase, arrowHeight和contentViewInsets方法。
- + (CGFloat)arrowBase
- {
- return kArrowBase;
- }
- + (CGFloat)arrowHeight
- {
- return kArrowHeight;
- }
- + (UIEdgeInsets)contentViewInsets
- {
- return UIEdgeInsetsMake(kBorderInset, kBorderInset, kBorderInset, kBorderInset);
- }
arrowBase方法確定arrow底部的寬度,arrowHeight方法確定arrow的高度。
Step 6
添加背景色,在initWithFrame:方法的條件語(yǔ)句中添加如下代碼:
- self.backgroundColor = [UIColor grayColor];
6.設(shè)置Popover Background View屬性
測(cè)試popover之前,我們需要輸入和設(shè)置popover controller的 popover Background View Class Property。打開ViewController.m文件,輸入 popover background view頭文件:
- #import "PopoverBackgroundView.h"
還是在ViewController.m文件中,位于我們?cè)趕howPopover:方法中創(chuàng)建UIPopoverController的下邊,添加下邊一行代碼,
- popController.popoverBackgroundViewClass = [PopoverBackgroundView class];
7.測(cè)試Popover Background View
創(chuàng)建、運(yùn)行項(xiàng)目,點(diǎn)擊“+”的按鈕來(lái)看下popover,可以看到標(biāo)準(zhǔn)的popover已經(jīng)被取代。
8.設(shè)置陰影和圓角
wantsDefaultContentAppearance 方法決定是否在popover中展示默認(rèn)的內(nèi)置陰影和圓角,如果返回的是“NO”,Popover Background View將不再展示默認(rèn)的陰影 和圓角,允許執(zhí)行你自己的。添加如下代碼來(lái)覆蓋之前的方法:
- + (BOOL)wantsDefaultContentAppearance
- {
- return NO;
- }
9.添加Arrow
Step 1
我們需要?jiǎng)?chuàng)建和管理arrow,我們可以為image view聲明一個(gè)屬性,在類擴(kuò)展中添加如下代碼:
- @property (nonatomic, strong) UIImageView *arrowImageView;
現(xiàn)在可以對(duì)image view進(jìn)行實(shí)例化,使用如下代碼替代initWithFrame:方法條件語(yǔ)句中的代碼:
- self.backgroundColor = [UIColor clearColor];
- UIImageView *arrowImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
- self.arrowImageView = arrowImageView;
- [self addSubview:self.arrowImageView];
Step 2
通過使用以下代碼來(lái)更新在PopoverBackgroundView.m定義的kBorderInset來(lái)改變border inset:
- #define kBorderInset 0.0f
Step 3
為了畫這個(gè)arrow,我們需要聲明一個(gè)方法來(lái)展現(xiàn),可以在PopoverBackgroundView.m類擴(kuò)展中添加下邊這個(gè)方法聲明:
- - (UIImage *)drawArrowImage:(CGSize)size;
Step 4
在@implementation下添加方法定義:
- - (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);
- CGPathAddLineToPoint(arrowPath, NULL, size.width, size.height);
- CGPathAddLineToPoint(arrowPath, NULL, 0.0f, size.height);
- CGPathCloseSubpath(arrowPath);
- CGContextAddPath(ctx, arrowPath);
- CGPathRelease(arrowPath);
- UIColor *fillColor = [UIColor yellowColor];
- CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
- CGContextDrawPath(ctx, kCGPathFill);
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return image;
- }
不用輸入圖片,上述代碼可以自動(dòng)生成一個(gè)arrow。
Step 5
每次popover的background view的子類的bounds 改變時(shí),這個(gè)arrow的frame需要重新計(jì)算。我們可以通過覆蓋layoutSubviews來(lái)達(dá)到目的,為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) kBorderInset), 0.0f, arrowSize.width, arrowSize.height);
- }
10. 測(cè)試Popover
源文件: