Autolayout:如何压缩复杂的弹出窗口

问题描述:

如果你喜欢尝试源代码(你是非常欢迎做),看看我的Bitbucket repositoryAutolayout:如何压缩复杂的弹出窗口

我有一个显示设置列表的popover对话框。这些设置列在多个UITableView中。 UITableViews不可滚动,因为整个设置视图已经是。此外,弹出式对话框应该尽可能垂直地放置屏幕,但是应该水平压缩。

因此,我设想以下结构:

UIView => MySettingsViewController 
- UIScrollView 
    - UIView (Content View) 
    - Container View1 
     - UITableView (embedded) => MyTableViewController 
    - Container View2 
     - UITableView (embedded) 

结构通过界面生成器组装和自动布局被用于上浆。

我有滚动视图,内容视图(我只有一个开始)和容器视图到它们各自的超级视图(或布局指南)。我约束的内容视图的大小以如下方式:

contentView.width == (topmost) UIView.width 
contentView.height == 200 // removed at build time 

另外,I设置表视图到其内容大小的大小,因为否则酥料饼显示为空:

class MyTableViewController: UITableViewController { 
    override func viewDidAppear(animated: Bool) { 
     super.viewDidAppear(animated) 
     // this is Cartography syntax - the intention should be clear 
     layout(view, replace: ConstraintGroup()) { [unowned self] view in 
      view.width == self.tableView.contentSize.width 
      view.height == self.tableView.contentSize.height 
     } 
     view.setNeedsLayout() 
    } 
} 

的设置酥料饼充满了内容,但它的大小是不完全正确:

enter image description here

为了解决这个问题,我尝试以下方法不工作:

class MySettingsViewController: UIViewController { 
    override var preferredContentSize: CGSize { 
     get { 
      let compressedSize = view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
      // this is always (0, 0) because the subviews are not resized, yet 
      return compressedSize 
     } 
     set { 
      super.preferredContentSize = newValue 
     } 
    } 
} 

总之:压缩不起作用。

所以我只是自己解决了这个问题,因为您可以看到Bitbucket存储库时看到的问题。

布局现在固定在MyTableViewControllerMySettingsViewController。前者现在看起来是这样的:

class MyTableViewController: UITableViewController { 

    var heightConstraint: NSLayoutConstraint? 
    var tableViewEdgesConstraints: [NSLayoutConstraint]? 

    override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 
     if let container = tableView.superview where tableViewEdgesConstraints == nil { 
      layout(tableView, container, replace: ConstraintGroup()) { [unowned self] tableView, container in 
       self.tableViewEdgesConstraints = tableView.edges == inset(container.edges, 0) 
      } 
     } 
    } 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 

     if let heightConstraint = heightConstraint { 
      if Int(heightConstraint.constant) != Int(tableView.contentSize.height) { 
       heightConstraint.constant = self.tableView.contentSize.height 
      } 
     } else { 
      layout(view, replace: ConstraintGroup()) { [unowned self] view in 
       if (self.tableView.contentSize.height > 0) { 
        self.heightConstraint = view.height == self.tableView.contentSize.height 
       } 
      } 
     } 
    } 
} 

所以基本上,我约束表其内容的高度的高度和改变约束,如果内容的高度变化。这是在桌子布置完成后立即完成的。此外,嵌套表格视图被其边缘固定到容器视图的边缘。我认为这是强制性的,因为我无法找到如何在Interface Builder中约束不同场景的两个视图。

MySettingsViewController滚动视图的大小设置为内容视图的框架的大小(可以通过插座访问),只要知道这个大小。此外,为了实现弹出式压缩,设置控制器的首选内容大小会相应地调整,当高度发生变化时(如果您忽略了您可能会陷入布局无限循环的情况,而且我做了3件事情,以便可以有一个围绕包裹MySettingsViewController导航控制器:

  1. 的酥料饼的宽度被设定为固定值(否则它有时会扩大到全宽度)。
  2. presentsViewController的preferredContentSize需要同等设置。
  3. 我必须将scrollView的insets设置为0以避免垂直偏移的丑陋 - 此解决方案是次优的,因为它会破坏滚动视图体验。但它的工作。

下面是代码:

class MySettingsViewController: UIViewController { 

    @IBOutlet weak var contentView: UIView! 
    @IBOutlet weak var scrollView: UIScrollView! 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 

     scrollView.contentSize = contentView.frame.size 

     if (preferredContentSize.height != scrollView.contentSize.height) { 
      let newSize = CGSize(width: 400, height: scrollView.contentSize.height) 
      preferredContentSize = newSize 
      presentingViewController?.presentedViewController?.preferredContentSize = newSize 
      scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) 
     } 
    } 
} 

这是结果:

enter image description here