【问题标题】:How do I adjust my popover to the size of the content in my tableview in swift?如何快速将弹出框调整为表格视图中内容的大小?
【发布时间】:2015-06-09 14:16:38
【问题描述】:

我正在使用popoverPresentationController 来显示我的弹出框。用于显示为弹出框的UITableViewController 是通过编程方式创建的,通常包含 1 到 5 行。如何设置此弹出框以根据 tableview 的内容调整大小?

我的弹出框代码:

if recognizer.state == .Began {
    let translation = recognizer.locationInView(view)

    // Create popoverViewController
    var popoverViewController = UITableViewController()
    popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
    popoverViewController.tableView.backgroundColor = UIColor.popupColor()

    // Settings for the popover
    let popover = popoverViewController.popoverPresentationController!
    popover.delegate = self
    popover.sourceView = self.view
    popover.sourceRect = CGRect(x: translation.x, y: translation.y, width: 0, height: 0)
    popover.backgroundColor = UIColor.popupColor()

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

【问题讨论】:

    标签: uitableview swift resize popover


    【解决方案1】:

    查看preferredContentSize property of UIViewController

    let height = yourDataArray.count * Int(popOverViewController.tableView.rowHeight)
    popOverViewController.preferredContentSize = CGSize(width: 300, height: height)
    

    【讨论】:

    • 谢谢,很简单。我之前尝试过preferredContentSize,但没有想到使用我的数组的计数:o。当我使用此解决方案时,它仅在我首先访问popoverViewController.tableView.rowHeight 后才有效,否则计数和高度将仅返回0。如果不先访问高度,我怎么能做到这一点?
    • 我通常在viewDidLoad中设置tableview.rowHeight = 44
    • 这假定了一个固定的行高,这并不理想。
    【解决方案2】:

    覆盖uitableviewcontroller 扩展中的preferredContentSize 属性,如下所示:

    override var preferredContentSize: CGSize {
        get {
            let height = calculate the height here....
            return CGSize(width: super.preferredContentSize.width, height: height)
        }
        set { super.preferredContentSize = newValue }
    }
    

    计算高度请查看tableView.rectForSection(<#section: Int#>)

    【讨论】:

    • 这是在行添加到我的表之前被调用的,所以rectForSection 的高度为零。
    • 有什么方法可以做到这一点并保持尺寸等级?在 iPad 上设置此属性会导致我看到我的 iPhone 布局。
    【解决方案3】:

    第一件事:所有的cmets都很好,帮助满满。 我的逻辑几乎没有做任何改变,这使我的 VC 成为可重用的组件。

    viewWillAppear:(BOOL)animated内部调用这个方法:

    -(void) setPopOverPreferedContentHeight {
    
         if (self.popoverPresentationController && self.tableView.contentSize.height < MAX_POPOVER_HEIGHT) {
              self.preferredContentSize=self.tableView.contentSize;
         } else if (self.popoverPresentationController){
             self.preferredContentSize = CGSizeMake(self.tableView.contentSize.width, MAX_POPOVER_HEIGHT);
       }
    }
    

    【讨论】:

      【解决方案4】:

      在你的 UITableViewController 的viewDidLoad() 中你可以添加一个观察者:

      self.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
      

      然后添加这个方法:

      override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
          self.preferredContentSize = tableView.contentSize
      }
      

      最后,在 viewDidDisappear() 中,确保删除观察者:

      tableView.removeObserver(self, forKeyPath: "contentSize")
      

      这样,无论何时加载或更改,弹出框都会自动调整大小以适应内容。

      【讨论】:

      • 感谢阿德里安和博的回答。我想在调整大小时禁用弹出框的动画。我怎样才能做到这一点?
      • @AdityaShinde 请将此作为另一个问题提出
      • 我对覆盖observeValue 方法感到不舒服。添加super方法崩溃了……难道不应该有更好的方法来观察变化吗?
      • @Trev14 observeValue 实际上是一种非常常见的观察关键路径变化的方法。你根本不应该打电话给超级。在那种方法中调用 super 是非常罕见的。顺便说一句,这个答案比其他答案要好得多,因为它不需要手动计算。
      • 啊,比任何其他解决方案都要好得多。太糟糕了 RXSwift 没有可观察的。而且我现在懒得写自己的了。
      【解决方案5】:

      对于 swift 4,如果您想观察内容大小,我发现这是最佳解决方案。因为网上没有找到完整的例子,所以在这里报告:

      class MyTableViewController: UITableViewController {
      
          private var kvoContext = 0
      
          override func viewWillAppear(_ animated: Bool) {
              super.viewWillAppear(animated)
              addObserver(self, forKeyPath: #keyPath(tableView.contentSize), options: .new, context: &kvoContext)
      
          }
      
          override func viewDidDisappear(_ animated: Bool) {
              removeObserver(self, forKeyPath: #keyPath(tableView.contentSize))
              super.viewDidDisappear(animated)
          }
      
          override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
              if context == &kvoContext, keyPath == #keyPath(tableView.contentSize),
                  let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize  {
                  self.popoverPresentationController?.presentedViewController.preferredContentSize = contentSize
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        Swift 4.xSwift 5.x 的简单动态答案,不涉及大小计算(Bo Frese 答案的现代版本):

        private var contentSizeObserver : NSKeyValueObservation?
        
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
        
            contentSizeObserver = tableView.observe(\.contentSize) { [weak self] tableView, _ in
                self?.preferredContentSize = CGSize(width: 320, height: tableView.contentSize.height) // Here I fixed the width but you can do whatever you want
            }
        }
        
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
        
            contentSizeObserver?.invalidate()
            contentSizeObserver = nil
        }
        

        【讨论】:

        • 你救了我的命!!
        • ⚠️ ⚠️ ⚠️ 对 KVO 完成块的 UI 处理应在主队列上运行。我编辑了上面的示例。
        • 你好@AntoineRucquoy,事实上,你不需要在主队列上运行它,因为它已经在它上面运行了。事实上,KVO 处理程序在执行修改的队列上运行。由于观察到的属性,这里\.contentSize,仅在主线程上更新(通过调用updateData 和朋友),您确定您的处理程序将在主线程上执行。
        • 你好@Zaphod,我在将我的 ViewController(我在 contentSize 的 UITableView 上使用 KVO)显示为移动设备(不是 iPad,奇怪的是)上的强制弹出窗口时发生了崩溃。也许这完全取决于我的项目是如何构建的。但是,我仍然认为在主线程上执行 UI 更改总是更安全。
        • @AntoineRucquoy 我同意,它总是更安全。但似乎您面临的问题只是一个症状,当您通过强制在主线程上调用来修复它时,您只是隐藏它。您应该首先检查为什么您的内容大小没有从主线程更新。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-19
        • 1970-01-01
        • 2011-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-02
        相关资源
        最近更新 更多