将视图控制器中的项目约束到导航栏中的项目

Posted

技术标签:

【中文标题】将视图控制器中的项目约束到导航栏中的项目【英文标题】:constrain item in viewcontroller to item in navigation bar 【发布时间】:2018-01-28 23:27:55 【问题描述】:

更新:

我原来的问题中提出的搜索栏和分段控制器如下所示:

我尝试在viewDidLoadBrowseViewController 中添加搜索栏作为导航控制器的子视图控制器(这不是导航控制器)

[self.navigationController addChildViewController:_searchController];
[self.navigationController.view addSubview:_searchController.searchBar];
_searchController.searchBar.frame = self.navigationController.navigationBar.bounds;
[_searchController didMoveToParentViewController:self.navigationController];

这会呈现:

我所看到的一切——分段控件、表格——都不见了。

更新 我试图将分段控件限制在viewWillLayoutSubviews 中的导航控制器视图中:

         _segmentedControl.translatesAutoresizingMaskIntoConstraints = NO;
           NSLayoutConstraint *segWidthConst = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:350];

          NSLayoutConstraint *segHeightConst = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:32];

        NSLayoutConstraint *segLeadingConstraint = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.navigationController.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:self.navigationController.navigationItem.titleView.frame.origin.x];

        NSLayoutConstraint *segVerticalConstraint = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.navigationController.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
        [_segmentedControl addConstraints:@[segWidthConst, segHeightConst, segLeadingConstraint, segVerticalConstraint]];

但我收到此错误:

US[5469:1553682] [LayoutConstraints] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x604000295810 UISegmentedControl:0x7face152bc90.leading == UILayoutContainerView:0x7face141a600.leading   (inactive)>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2018-01-28 22:18:29.402296-0500 Leaflet-US[5469:1553682] *** Assertion failure in -[UISegmentedControl _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/NSLayoutConstraint_UIKitAdditions.m:734
Impossible to set up layout with view hierarchy unprepared for constraint.
(null)

我有一个 UI 搜索控制器,我创建并放入我的导航控制器内 viewDidLoad:

/*set appearance of search controller */
_searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
_searchController.searchBar.delegate = self;
_searchController.searchResultsUpdater = self;
[_searchController.searchBar sizeToFit];
_searchController.dimsBackgroundDuringPresentation = NO;
self.definesPresentationContext = YES;
_searchController.hidesNavigationBarDuringPresentation = NO;
_searchController.searchBar.searchBarStyle = UISearchBarStyleDefault;
[self.navigationController.navigationBar setBarTintColor:[UIColor blackColor]];
self.navigationController.navigationBar.translucent = NO;
self.navigationItem.titleView = self.searchController.searchBar;

我的视图中还有一个分段控件。我想将分段控件的前导约束与搜索栏的前导约束对齐。

我尝试在viewWillLayoutSubviews这样做

_segmentedControl.translatesAutoresizingMaskIntoConstraints = NO;
   NSLayoutConstraint *segWidthConst = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:350];

  NSLayoutConstraint *segHeightConst = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:32];

NSLayoutConstraint *segLeadingConstraint = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:_searchController.searchBar attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0];

NSLayoutConstraint *segVerticalConstraint = [NSLayoutConstraint constraintWithItem:_segmentedControl attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view.safeAreaLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0];
[_segmentedControl addConstraints:@[segWidthConst, segHeightConst, segLeadingConstraint, segVerticalConstraint]];

但是,这样做会使应用程序崩溃:

[LayoutConstraints] The view hierarchy is not prepared for the constraint: 
        <NSLayoutConstraint:0x600000486180 UISegmentedControl:0x7fa647e13620.leading == UISearchBar:0x7fa647f258f0.leading   (inactive)>
When added to a view, the constraint's items must be descendants of that view (or the view itself). 
This will crash if the constraint needs to be resolved before the view hierarchy is assembled. 
Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2018-01-28 18:21:14.589089-0500 Leaflet-US[3891:804350] *** Assertion failure in 
-[UISegmentedControl _layoutEngine_didAddLayoutConstraint:roundingAdjustment:
    mutuallyExclusiveConstraints:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/NSLayoutConstraint_UIKitAdditions.m:734
Impossible to set up layout with view hierarchy unprepared for constraint.

在查看视图调试时,我发现搜索栏确实不是我的视图控制器的后代(与分段控件不同)。

-UITabBarController 
 -UILayoutContainerView 
  -UitransitionView
   -UIViewControllerWrapperView 
    -UINavigationController
     -UILayoutContainerView
      -UINavigationTransitionView 
       -UIViewControllerWrapperView
        -BrowseViewController 
         -UIView 
          -UISegmentedControl
      -UINavigationBar
       -UIBarBackground
       -UINavigationBarContentView
        -UISearchBar

如果搜索容器视图控制器本身包装在 UINavigationController 中,我如何将分段控件约束到搜索栏?

【问题讨论】:

你认为层次结构是什么样的? @dudeman 感谢您指出这一点 - 我已将其添加到我的帖子中 我试图将分段控制限制在导航控制器的视图中,但我得到了Impossible to set up layout with view hierarchy unprepared for constraint 【参考方案1】:

您可以尝试以下几种方法:

1) 只在分段控件中添加segWidthConstsegHeightConst;并将其他两个约束添加到导航控制器。

2) 获取_searchController.searchBar 与导航控制器相关的框架,然后使用框架的 x 作为常量将分段控制器固定到导航控制器的视图。

【讨论】:

我尝试了第一个并得到,Impossible to set up layout with view hierarchy unprepared for constraint. 除非我能成功地将分段控件约束到导航控制器视图,否则我似乎无法尝试第二个? 也许尝试在viewWillAppear 中添加约束而不是viewDidLoad 我实际上是在viewWillLayoutSubviews 中添加约束,但我可以试试 viewWillAppear 我尝试了viewWillAppear 并得到了同样的崩溃 我刚刚注意到的一件事是您没有将搜索控制器添加为导航控制器的子视图控制器。那么也许可以尝试完成这个过程?【参考方案2】:

您应该知道的一件事是,您必须在用于定义它的视图的最近祖先视图上添加一个约束。所以,显然你不应该在段控制上添加前导约束。并且根据视图层次,你可以尝试在 UINavigationController 的 UILayoutContainerView 上添加约束,因为它似乎是最近的祖先视图。

【讨论】:

以上是关于将视图控制器中的项目约束到导航栏中的项目的主要内容,如果未能解决你的问题,请参考以下文章

在导航到另一个视图控制器之前切换标签栏

单击导航栏中的“返回”按钮时如何设置自定义视图控制器?

iPad 应用程序中的旋转

故事板下添加的导航项

多个导航控制器中的视图控制器通信

从推送视图访问第一个导航控制器中的方法和变量