【问题标题】:iOS 8 - UIPopoverPresentationController moving popoveriOS 8 - UIPopoverPresentationController 移动弹出框
【发布时间】:2014-08-18 20:57:09
【问题描述】:

我正在寻找一种使用新的 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 时得到无法识别的选择器 我已经根据文档设置了委托,仍然没有运气。
  • 我想出了一个:在 viewWillAppear 中设置大小
  • 好电话。我的尺寸仍在使用这个委托方法......
  • @mehinger 你有没有想过移动 uipopoverpresentationcontroller?
  • @Amendale 我从来没有这样做过。放弃并改用自定义 UIView

标签: popover ios8


【解决方案1】:

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

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

这会临时更改呈现视图的内容大小,从而重新定位弹出框和箭头。大小的临时变化是不可见的。

这似乎是 Apple 需要解决的一个问题 - 更改 UIPopoverPresentationControllersourceViewsourceRect 属性在它已经呈现一个弹出框时不起作用(没有此解决方法)。

希望这对你也有用!

【讨论】:

  • 同样的问题,但在 iOS7 中没有问题!
  • 这似乎仍然是(2016 年,iOS 9)是实现这项工作的唯一方法。您可以将preferredContentSize 设置回原来的值,但是您必须先实际更改它,并且不能设置为CGSizeZero
  • 仍然需要(2017,部署目标 iOS 9,SDKROOT iOS 11.2,Xcode 9.2)。
  • aaa 更糟糕的是,在 iOS12 中,他们将 preferredContentSize 设置为不可变,因此如果您愿意,您甚至无法使用此 hack。
【解决方案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,来确保popover在移动后移动到正确的位置。

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

【讨论】:

    【解决方案3】:

    我使用了与@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 相同,这也会导致弹出框被更新,即使它的大小实际上并没有改变。

    【讨论】:

      【解决方案4】:

      我发布此内容是因为我没有足够的积分来投票或发表评论。 :) @turbs 的回答非常适合我。这应该是公认的答案。

      在委托方法中将 *rect 设置为您需要的 rect:

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

      【讨论】:

        【解决方案5】:

        在更改了popoverPresentationControllersourceRect 之后,我很幸运地使用了containerView?.setNeedsLayout()containerView?.layoutIfNeeded(),如下所示:

        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 的工作就像魅力一样......你有很好的知识
        【解决方案6】:

        iOS 12.3

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

        【讨论】:

          猜你喜欢
          • 2014-10-08
          • 2015-02-05
          • 1970-01-01
          • 2014-09-11
          • 2014-08-29
          • 1970-01-01
          • 2018-05-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多