弹出框没有在按钮中心显示

20

我试图将弹出框居中于一个按钮上,但是我似乎无法找出我的问题所在。箭头没有在按钮中间,而是偏移了半个屏幕的宽度。

 @IBAction func buttonClicked(sender: AnyObject){
    var popoverViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ServiceOptions") as! ServiceOptionsPopover
    popoverViewController.delegate = self
    popoverViewController.modalPresentationStyle = .Popover
    popoverViewController.preferredContentSize   = CGSizeMake(300, 300)

    let popoverPresentationViewController = popoverViewController.popoverPresentationController

    popoverPresentationViewController?.permittedArrowDirections = .Up
    popoverPresentationViewController?.delegate = self
    popoverPresentationViewController?.sourceView = sender as! UIButton
    popoverPresentationViewController?.sourceRect = sender.frame

    presentViewController(popoverViewController, animated: true, completion: nil)
}

https://www.dropbox.com/s/99qjhqna07t1iwc/popover.png?dl=0 - user3642915
4个回答

60
问题在于混淆了“帧”和“边界”的概念。
popoverPresentationViewController?.sourceView = sender as! UIButton
popoverPresentationViewController?.sourceRect = sender.frame

不对!你的意思是界限:

popoverPresentationViewController?.sourceView = sender as! UIButton
popoverPresentationViewController?.sourceRect = (sender as! UIButton).bounds
原因是 sourceRect 是在 sourceView 的坐标空间中给出的 - 也就是说,如果希望它是视图的矩形,则为该视图的边界。

49
iOS 9存在问题。在Storyboard中设置锚点:enter image description here,导致箭头不居中于锚点:enter image description here。要解决此问题,请在prepareForSegue:sender:中添加以下内容:
// Fixes popover anchor centering issue in iOS 9
if let popoverPresentationController = segue.destinationViewController.popoverPresentationController, sourceView = sender as? UIView {
  popoverPresentationController.sourceRect = sourceView.bounds
}

输入图像描述


1
非常好的回答。截图帮助我确定这正是我遇到的问题。 - Frederic Adda
2
对我不起作用。我正在使用这段代码。let popoverViewController = segue.destinationViewControllerpopoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover popoverViewController.popoverPresentationController!.delegate = self如果segue.destinationViewController.popoverPresentationController存在,且sender是UIView类型,则设置sourceRect为sender的bounds。 - Ada
对我来说运行得非常好! - fivewood

3
这是正确的方法:
@IBAction func buttonClicked(sender: UIButton){
    var popoverViewController = UIViewController()
    popoverViewController.view.frame = CGRectMake(0,0, 300, 300)
    popoverViewController.view.backgroundColor = UIColor.redColor()
    popoverViewController.modalPresentationStyle = .Popover
    popoverViewController.preferredContentSize   = CGSizeMake(300, 300)

    let popoverPresentationViewController = popoverViewController.popoverPresentationController

    popoverPresentationViewController?.permittedArrowDirections = .Up
    popoverPresentationViewController?.sourceView = sender
    popoverPresentationViewController?.sourceRect = CGRectMake(0, 0, sender.bounds.width,sender.bounds.height) // see this line of code

    presentViewController(popoverViewController, animated: true, completion: nil)
}

2

在我的情况下,问题是不同的,弹出窗口显示的是一个带有自定义视图的UIBarButtonItem。对于iOS 11,如果您使用UIBarButtonItem的自定义视图,则需要使自定义视图符合自动布局规则。

使用此类别,您可以快速应用约束。

UIView+NavigationBar.h

@interface UIView (NavigationBar)

    - (void)applyNavigationBarConstraints:(CGFloat)width height:(CGFloat)height;
    - (void)applyNavigationBarConstraintsWithCurrentSize;

@end

UIView+NavigationBar.m

#import "UIView+NavigationBar.h"

@implementation UIView (NavigationBar)

- (void)applyNavigationBarConstraints:(CGFloat)width height:(CGFloat)height
{
    if (width == 0 || height == 0) {
        return;
    }

    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:width];
    [heightConstraint setActive:TRUE];
    [widthConstraint setActive:TRUE];
}

- (void)applyNavigationBarConstraintsWithCurrentSize {
    [self applyNavigationBarConstraints:self.bounds.size.width height:self.bounds.size.height];
}

@end

然后你可以执行以下操作:
UIButton *buttonMenu = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonMenu setImage:[UIImage imageNamed:@"menu"] forState:UIControlStateNormal];
buttonMenu.frame = CGRectMake(0, 0, 44, 44);
[buttonMenu addTarget:self action:@selector(showMenu:) forControlEvents:UIControlEventTouchUpInside];

//Apply constraints 
[buttonMenu applyNavigationBarConstraintsWithCurrentSize];

UIBarButtonItem *menuBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:buttonMenu];

一旦您应用了约束条件,弹出窗口将正确显示在自定义视图上,例如,显示警报作为弹出窗口的代码如下:

UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Menu" message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
//Add actions ....

UIPopoverPresentationController *popController = [controller popoverPresentationController];
popController.sourceView = buttonMenu;
popController.sourceRect = buttonMenu.bounds;

[self presentViewController:controller animated:YES completion:nil];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接