iOS 8 - UIPopoverPresentationController移动弹出窗口

时间:2014-06-27 16:52:59

标签: popover ios8

我正在寻找一种使用新的uipopoverpresentationcontroller重新定位弹出窗口的有效方法。我已经成功地呈现了弹出窗口,现在我想移动它而不会解散并再次呈现。我在使用该功能时遇到问题:

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

我知道这是游戏的早期,但任何人都有一个如何有效地做到这一点的例子我会很感激,如果你与我分享。提前致谢。

6 个答案:

答案 0 :(得分:14)

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

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

这会暂时更改显示视图的内容大小,从而导致弹出窗口和箭头重新定位。暂时改变大小不可见。

这似乎是Apple需要解决的问题 - 更改sourceView的{​​{1}}或sourceRect属性时,如果它已经提供了一个popover(没有此解决方法)则不会执行任何操作)。

希望这也适合你!

答案 1 :(得分:5)

在更改containerView?.layoutIfNeeded()的{​​{1}}之后,我在sourceRectpopoverPresentationController上运气不错,就像这样:

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

甚至让popover跟随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()
        }
    }
}

答案 2 :(得分: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相同,这也会导致更新popover,即使它的大小实际上没有变化。

答案 3 :(得分:2)

以下是如何重新定位popover的示例:

- (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和*视图设置为原始sourceRect和sourceView来确保弹出窗口移动到正确的位置。

作为补充说明,我不相信当使用条形按钮项设置弹出框的源时调用此方法。

答案 4 :(得分:1)

我发布此信息是因为我没有足够的积分进行投票或评论。 :) @turbs的回答对我很有帮助。这应该是公认的答案。

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

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

答案 5 :(得分:-1)

iOS 12.3

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