前言
最近項目中很多地方有一個相同的需求,那就是點擊一個按鈕的時候在按鈕的某一個方向彈出一個視圖,這個視圖需要帶有一個箭頭指向,就像下圖一樣。要實現這個功能,就要用到UIPopoverPresentationController這個類了。

WechatIMG38.jpeg
簡介
一個帶有箭頭的彈出視圖從出現到消失的整個過程,都是UIPopoverPresentationController類的實例在管理,UIPopoverPresentationController類的實例管理着彈出視圖的外形和其它的一些性質。
我們不需要直接去創建這個類的對象,當我們把這個彈出視圖對應的視圖控制器的modalPresentationStyle
屬性設置為UIModalPresentationPopover
時,viewcontroller就會擁有一個popoverPresentationController
屬性,它就是UIPopoverPresentationController類型的,用它來管理這個彈出視圖的外形和其它一些性質。
UIPopoverPresentationControllerDelegate
UIPopoverPresentationControllerDelegate對象會通知它的delegate整個彈出視圖從彈出到消失的整個過程。下面是其主要的API:
通知delegate視圖將要呈現:
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController;
詢問delegate視圖是否應該消失
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController;
通知delegate視圖已經消失
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController;
相關屬性

3E798BC1-2CF1-4634-8859-9EA7515BE1E4.png
- backgroundColor
上圖中設置的backgroundColor是紅色,上圖中彈出視圖是由兩部分疊加的,一部分是上面的viewcontroller的View,其背景色是黃色,還有一部分是承載viewcontroller的View的視圖,這個視圖是由viewcontroller的popoverPresentationController對象來管理的。 - passthroughViews
這是一個數組,里面裝着視圖,一般情況下在彈出視圖可見的情況下,點擊界面上其他視圖是無效的,這會導致彈出視圖消失,但是這個數組中的視圖不會這樣,在彈出視圖可見的情況下仍然可以點擊這些視圖。 - canOverlapSourceViewRect
這是一個布爾值,說明彈出視圖是否可以和sourceRect重疊。 - sourceView
這個屬性其實就是要指出彈出視圖的箭頭要指向哪個視圖。 - permittedArrowDirections
這個屬性要確定彈出視圖的箭頭的方法,它是一個枚舉值,上圖中設置的箭頭方向是左邊。 - sourceRect
有了sourceView和permittedArrowDirections還不能完全確定箭頭的位置,還需要一個參數,這個參數就是sourceRect。上圖中設置的sourceRect為_button.bnounds,當我們把sourceRect設置為CGRectMake(0, 0, _button.bounds.size.width, _button.bounds.size.height / 2.0);
也即是這個按鈕的上半區域的時候,我們看一下效果:
0D46A23E-3BF1-4241-8A06-1BB92235F068.png
簡單應用
TestViewController *testVC = [[TestViewController alloc] init]; testVC.preferredContentSize = CGSizeMake(150, 150); testVC.modalPresentationStyle = UIModalPresentationPopover; testVC.popoverPresentationController.delegate = self; testVC.popoverPresentationController.sourceView = _button; testVC.popoverPresentationController.sourceRect = CGRectMake(0, 0, _button.bounds.size.width / 2.0, _button.bounds.size.height / 2.0); testVC.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionLeft; testVC.popoverPresentationController.backgroundColor = [UIColor redColor]; testVC.popoverPresentationController.canOverlapSourceViewRect = NO; [self presentViewController:testVC animated:YES completion:^{ }];
注意,這樣做的話是無論如何都不能成功顯示彈出視圖的,我們還需要實現代理的一個方法:
#pragma mark - <UIPopoverPresentationControllerDelegate> - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller { return UIModalPresentationNone; }
這樣就能成功實現了。