IOS8上的 UIPopoverPresentationController

有人知道 UIPopoverPresentationController是否可以用来在 iPhone 上展示泡芙吗?想知道苹果是否在 iOS8上添加了这个功能,以便为 iPad 和 iPhone 创建一个更统一的展示控制器。

不确定是否可以问/回答来自 Beta 的问题。在这种情况下我会删除它。

60754 次浏览

方法覆盖默认的自适应行为(紧凑水平环境中的 UIModalPresentationFullScreen,即 iPhone) 通过 UIPopoverPresentationController.delegate提供的 adaptivePresentationStyleForPresentationController:方法。

UIPresentationController使用这个方法来要求使用新的表示样式,在您的例子中,简单地返回 UIModalPresentationNone将导致 UIPopoverPresentationController以弹出窗口而不是全屏的形式呈现。

下面是一个弹出的例子,它使用故事板中从 UIBarButtonItem到“ 情态现在UIViewController的接续设置

class SomeViewController: UIViewController, UIPopoverPresentationControllerDelegate {


// override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // swift < 3.0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PopoverSegue" {
if let controller = segue.destinationViewController as? UIViewController {
controller.popoverPresentationController.delegate = self
controller.preferredContentSize = CGSize(width: 320, height: 186)
}
}
}


// MARK: UIPopoverPresentationControllerDelegate


//func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle { // swift < 3.0
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}
}

这个技巧在 WWDC 2014第214届会议“ iOS8中视图控制器的进步”(36:30)中提到过

在 WEBVIEW 类中添加这两个方法

-(void) prepareForSegue: (UIStoryboardSegue * ) segue sender: (id) sender {
// Assuming you've hooked this all up in a Storyboard with a popover presentation style
if ([segue.identifier isEqualToString: @"showPopover"]) {
UINavigationController * destNav = segue.destinationViewController;
pop = destNav.viewControllers.firstObject;
// This is the important part
UIPopoverPresentationController * popPC = destNav.popoverPresentationController;
popPC.delegate = self;
}
}


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

如果有人希望仅用代码呈现弹出窗口,可以使用以下方法。

目的 C

声明 UIPopoverPresentationController的属性:

@property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;

使用以下方法显示来自 UIButton 的 popover:

- (IBAction)btnSelectDatePressed:(id)sender
{
UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
dateVC.preferredContentSize = CGSizeMake(280,200);
destNav.modalPresentationStyle = UIModalPresentationPopover;
_dateTimePopover8 = destNav.popoverPresentationController;
_dateTimePopover8.delegate = self;
_dateTimePopover8.sourceView = self.view;
_dateTimePopover8.sourceRect = sender.frame;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
}

使用以下方法显示来自 UIBarButtonItem 的弹出窗口:

- (IBAction)btnSelectDatePressed:(id)sender
{
UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
dateVC.preferredContentSize = CGSizeMake(280,200);
destNav.modalPresentationStyle = UIModalPresentationPopover;
_dateTimePopover8 = destNav.popoverPresentationController;
_dateTimePopover8.delegate = self;
_dateTimePopover8.sourceView = self.view;
CGRect frame = [[sender valueForKey:@"view"] frame];
frame.origin.y = frame.origin.y+20;
_dateTimePopover8.sourceRect = frame;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
}

在视图控制器中也实现此委托方法:

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

要解除这个弹出窗口,只需解除视图控制器:

-(void)hideIOS8PopOver
{
[self dismissViewControllerAnimated:YES completion:nil];
}

SWIFT

使用以下方法显示来自 UIButon 的 popover:

func filterBooks(sender: UIButon)
{
let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = .Any
popoverPresentationViewController?.delegate = self
popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
popoverPresentationViewController!.sourceView = self.view;
popoverPresentationViewController!.sourceRect = sender.frame


filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
filterDistanceViewController.navigationBarHidden = true
self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
}

使用以下方法显示来自 UIBarButtonItem 的弹出窗口:

func filterBooks(sender: UIBarButtonItem)
{
let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = .Any
popoverPresentationViewController?.delegate = self
popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
popoverPresentationViewController!.sourceView = self.view;
var frame:CGRect = sender.valueForKey("view")!.frame
frame.origin.y = frame.origin.y+20
popoverPresentationViewController!.sourceRect = frame


filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
filterDistanceViewController.navigationBarHidden = true
self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
}

在视图控制器中也实现此委托方法:

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
return .None
}

请确保将代理 UIPopoverPresentationControllerDelegate添加到. h/. m/. swift 文件中

我找到了一些解决办法。

在 Xcode6.1上,使用 presentationController.delegate而不是 popoverPresentationController.delegate

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier compare:@"showPopOver"] == NSOrderedSame) {
UINavigationController * nvc = segue.destinationViewController;
UIPresentationController * pc = nvc.presentationController;
pc.delegate = self;
}
}


#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}

在 WWDC 2014“查看 iOS8中的控制器升级”中,以下代码可以在 iPhone 上显示 popover。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{


UINavigationController * nvc = segue.destinationViewController;
UIPopoverPresentationController * pvc = nvc.popoverPresentationController;
pvc.delegate = self;
}


#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}

但是在 Xcode 6.1上,这些代码显示了 FullScreen 演示..。 (nvc.popoverPresentationController 为空)

我怀疑这可能是苹果的漏洞。

确保实现 控制代理

像这样:

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

如果你不想要全屏泡芙

问题: iPhone popover 显示全屏且不尊重 preterredContentSize 值。

解决方案: 与 Apple 在 UIPopoverPresentationController Class 引用中的建议相反,提供视图控制器 之后获取对 popover 表示控制器的引用并对其进行配置。

// Get the popover presentation controller and configure it.
//...


// Present the view controller using the popover style.
[self presentViewController:myPopoverViewController animated: YES completion: nil];

在 iOS 8.3及更高版本中,在 UIPopoverPresentationControllerDelegate协议中使用以下语法覆盖弹出窗口的 UIModalPresentationStyle

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}

您可以像下面这样扩展 UIPopoverPresentationController 委托:

protocol PopoverPresentationSourceView {}
extension UIBarButtonItem : PopoverPresentationSourceView {}
extension UIView : PopoverPresentationSourceView {}


extension UIPopoverPresentationControllerDelegate where Self : UIViewController {
func present(popover: UIViewController,
from sourceView: PopoverPresentationSourceView,
size: CGSize, arrowDirection: UIPopoverArrowDirection) {


popover.modalPresentationStyle = .popover
popover.preferredContentSize = size
let popoverController = popover.popoverPresentationController
popoverController?.delegate = self
if let aView = sourceView as? UIView {
popoverController?.sourceView = aView
popoverController?.sourceRect = CGRect(x: aView.bounds.midX, y: aView.bounds.midY, width: 0, height: 0)
} else if let barButtonItem = sourceView as? UIBarButtonItem {
popoverController?.barButtonItem = barButtonItem
}
popoverController?.permittedArrowDirections = arrowDirection
present(popover, animated: true, completion: nil)
}
}

现在可以从实现 UIPopoverPresentationControllerDelegate的任何视图控制器调用 present(popover: from: size: arrowDirection: ),例如。

class YourViewController : UIViewController {
@IBAction func someButtonPressed(_ sender: UIButton) {
let popover = SomeViewController()
present(popover: popover, from: sender, size: CGSize(width: 280, height: 400), arrowDirection: .right)
}
}


extension YourViewController : UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}

在 UIAdaptivePresentationController 委托中,必须使用此方法:

func adaptivePresentationStyle(for: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle

而不是这样:

func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle