iOS 8 - UIPopoverPresentationController移动弹出窗口

20

我正在寻找一种使用新的UIPopoverPresentationController重新定位弹出窗口的有效方法。 我已经成功地呈现了弹出窗口,现在我想移动它而不用关闭再重新呈现。 我在使用函数时遇到了问题:

(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
      willRepositionPopoverToRect:(inout CGRect *)rect
                           inView:(inout UIView **)view

我知道现在还比较早,但如果有人能提供一个高效的方法示例,我会非常感激。先谢谢了。


我也遇到了同样的问题。我在调整弹出窗口大小时遇到了困难(它似乎忽略了popoverLayoutMargins和popoverContentSize)。当我实现_(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect )rect inView:(inout UIView *)view_时,我得到了未识别的选择器。根据文档,我已经设置了委托,但仍然没有运气。 - Rufus
我想通了:在viewWillAppear中设置大小。 - angerboy
好的,我的尺寸调整还在工作中,我还在研究这个委托方法... - Rufus
@mehinger 你最终解决了移动UIPopoverPresentationController的问题吗? - Amendale
@Amendale 我从来没有这样做过。放弃了,改用自定义的UIView。 - angerboy
@mehinger 是的,我也采取了同样的解决方案... - Amendale
6个回答

16

不幸的是,这个笨拙的解决办法是我找到的唯一解决方案:

[vc.popoverPresentationController setSourceRect:newSourceRect];
[vc setPreferredContentSize:CGRectInset(vc.view.frame, -0.01, 0.0).size];

这将暂时改变呈现视图的内容大小,导致弹出窗口和箭头被重新定位。临时更改的大小不可见。

似乎这是一个苹果需要修复的问题 - 改变UIPopoverPresentationControllersourceViewsourceRect属性在已经弹出一个弹窗时(没有此解决方法)不起作用。

希望这对你也有用!


这里也有同样的问题,但在iOS7中没有问题! - gdm
这似乎仍然(2016年,iOS 9)是使其工作的唯一方法。您可以将“preferredContentSize”设置回其原始值,但必须先实际更改它,而且不能为“CGSizeZero”。 - skagedal
1
仍需要(2017年,部署目标为iOS 9,SDKROOT为iOS 11.2,Xcode 9.2)。 - Thorsten
1
而更糟糕的是,在iOS12中,他们使preferredContentSize成为不可变的,因此即使您想使用此方法,也无法使用。 - Geoff H

9

我曾经用过containerView?.setNeedsLayout()containerView?.layoutIfNeeded()方法,在改变popoverPresentationControllersourceRect后,它们非常有帮助:

func movePopoverTo(_ newRect: CGRect) {
    let popover = self.presentedViewController as? MyPopoverViewController {
        popover.popoverPresentationController?.sourceRect = newRect
        popover.popoverPresentationController?.containerView?.setNeedsLayout()
        popover.popoverPresentationController?.containerView?.layoutIfNeeded()
    }
}

甚至可以在不更改任何内容的情况下使弹出框跟随tableView单元格:

class MyTableViewController: UITableViewController {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "MyPopoverSegue" {
            guard let controller = segue.destination as? MyPopoverViewController else { fatalError("Expected destination controller to be a 'MyPopoverViewController'!") }
            guard let popoverPresentationController = controller.popoverPresentationController else { fatalError("No popoverPresentationController!") }
            guard let rowIndexPath = sender as? IndexPath else { fatalError("Expected sender to be an 'IndexPath'!") }
            guard myData.count > rowIndexPath.row else { fatalError("Index (\(rowIndexPath.row)) Out Of Bounds for array (count: \(myData.count))!") }
            if self.presentedViewController is MyPopoverViewController {
                self.presentedViewController?.dismiss(animated: false)
            }
            popoverPresentationController.sourceView = self.tableView
            popoverPresentationController.sourceRect = self.tableView.rectForRow(at: rowIndexPath)
            popoverPresentationController.passthroughViews = [self.tableView]
            controller.configure(myData[rowIndexPath.row])
        }
        super.prepare(for: segue, sender: sender)
    }
}

// MARK: - UIScrollViewDelegate

extension MyTableViewController {
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let popover = self.presentedViewController as? MyPopoverViewController {
            popover.popoverPresentationController?.containerView?.setNeedsLayout()
            popover.popoverPresentationController?.containerView?.layoutIfNeeded()
        }
    }
}

谢谢,setneedslayout和layoutifneeded非常好用...你拥有很好的知识。 - Naresh

4

我使用了与@Rowan_Jones在另一个答案中提到的相同方法,但是我不希望浮动窗口的大小实际上改变。即使是一点点的分数也不行。我意识到,您可以将preferredContentSize多次设置为连续的,但在视觉上,其大小只会更改以匹配最后一个值。

[vc.popoverPresentationController setSourceRect:newSourceRect];
CGSize finalDesiredSize = CGSizeMake(320, 480);
CGSize tempSize = CGSizeMake(finalDesiredSize.width, finalDesiredSize.height + 1);
[vc setPreferredContentSize:tempSize];
[vc setPreferredContentSize:finalDesiredSize];

因此,即使finalDesiredSize与您的初始preferredContentSize相同,这也会导致弹出窗口被更新,尽管其大小实际上并没有改变。

2

这里是如何重新定位弹出框的示例:

- (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect *)rect     inView:(inout UIView **)view {

     *rect = CGRectMake((CGRectGetWidth((*view).bounds)-2)*0.5f,(CGRectGetHeight((*view).bounds)-2)*0.5f, 2, 2);

我还使用了这种方法来确保在移动时,将*rect和*view设置为原始的sourceRect和sourceView,以确保弹出窗口移动到正确的位置。

另外需要注意的是,当弹出窗口的源使用一个bar按钮项时,我不认为会调用这种方法。


1

我发布这篇文章是因为我没有足够的积分来投票或评论。 :) @turbs的答案对我完美地起作用了。它应该被接受的答案。

在委托方法中将*rect设置为所需的矩形:

(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
    willRepositionPopoverToRect:(inout CGRect *)rect     
        inView:(inout UIView **)view

-1

iOS 12.3

[vc.popoverPresentationController setSourceRect:newSourceRect]; [vc.popoverPresentationController.containerView setNeedsLayout];


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