以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用

Posted

技术标签:

【中文标题】以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用【英文标题】:Adding subview to UICollectionView using auto layout programmatically not working 【发布时间】:2014-08-08 19:54:31 【问题描述】:

我从情节提要设置了UICollectionViewController,它使用流式布局。到目前为止,它工作正常,即它的布局和单元格按预期工作。

现在,我正在尝试将UISearchBar 作为子视图添加到UICollectionView。这就是我添加搜索栏的方式:

流程布局的sectionInset 设置为UIEdgeInsetsMake(44, 0, 0, 0) 为搜索栏腾出空间。

并在viewDidLoad中添加如下代码:

self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 768.0, 44.0f)];
    // have also tried [[UISearchBar alloc] init] here.
[self.searchBar setTranslatesAutoresizingMaskIntoConstraints:NO];

[self.collectionView addSubview:self.searchBar];

NSDictionary* viewDict = @@"mySearchBar": self.searchBar;

NSArray* sHorizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mySearchBar]|"
                                                               options:0
                                                               metrics:nil
                                                                 views:viewDict];


NSArray* sVertical = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mySearchBar(==44)]"
                                                             options:0
                                                             metrics:nil
                                                               views:viewDict];

[self.collectionView addConstraints:sHorizontal];
[self.collectionView addConstraints:sVertical];

约束非常简单。 searchBar 的左、右和上边缘固定在父视图的左、右和上边缘,其高度为 44。

问题是运行此代码时搜索栏不可见。我在viewDidAppear 中记录了searchBar 的帧值,发现它的帧设置为(0, 0, 0, 44),即宽度没有得到解决。

我还尝试了可视格式字符串H:|[mySearchBar(>=768)]|,在这种情况下,searchBar 是可见的并且在它的位置,但不会在方向更改时调整大小,即在横向上也保持 768 点宽。

我在这里做错了什么?应该怎么做才能使所需的布局约束起作用?

我正在 iPad 模拟器 ios 7.1 上尝试这个。

我也尝试将搜索栏添加到标题视图,但它的行为与我需要的不同。

【问题讨论】:

如果viewDidLoad 中有搜索栏,为什么还要以编程方式添加搜索栏?它似乎独立于任何其他事件。 这是我添加到 viewDidLoad 以获得搜索栏的代码。它不在那里。 searchBar 是我添加的属性。 【参考方案1】:

解决了!

我仍然不确定为什么以前的方法不起作用,但我得到了这样的预期结果:

NSDictionary* viewDict = @@"mySearchBar": self.searchBar, @"myCollView": self.collectionView;

NSArray* sHorizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mySearchBar(==myCollView)]|"
                                                               options:0
                                                               metrics:nil
                                                                 views:viewDict];


NSArray* sVertical = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mySearchBar(==44)]"
                                                             options:0
                                                             metrics:nil
                                                               views:viewDict];

[self.collectionView addConstraints:sHorizontal];
[self.collectionView addConstraints:sVertical];

注意视觉格式字符串H:|[mySearchBar(==myCollView)]|,这意味着搜索栏的宽度应该等于集合视图的宽度。集合视图作为myCollView 添加到viewDict 字典中。这按预期工作,搜索栏会根据方向变化调整大小。

需要注意的几点,之前我也尝试过使用NSLayoutConstraint 类的constraintWithItem: 方法。虽然 api 相当容易理解,但它只创建一个约束。所以我们必须根据所需的约束数量多次调用它,这可能很乏味。不仅如此,就我而言,使用这种方法设置“等宽”约束会崩溃,我不知道为什么。

另一方面,constraintsWithVisualFormat: 返回一个数组,其中包含满足可视格式字符串中的条件所需的所有约束。

【讨论】:

【参考方案2】:

好吧,如果它是您想要的搜索栏,您可能希望它位于您的 collectionView 的正上方。这在情节提要中非常简单:您只需将搜索栏和搜索显示控制器拖到您的收藏视图上即可。但是,如果您必须以编程方式执行此操作,那么应该可以这样做:

- (void)viewDidLoad

    [super viewDidLoad];
    [self.collectionView registerClass:[UISearchBar class]
            forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                   withReuseIdentifier:@"reuseIdentifier"];



- (UIView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

    static NSString *reuseIdentifier = @"reuseIdentifier";
    UISearchBar *searchBar = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                                withReuseIdentifier:reuseIdentifier
                                                                       forIndexPath:indexPath];
    searchBar.delegate = self;
    return searchBar;

【讨论】:

是的,我知道这一点。请看问题的最后一行。它的行为不符合我的要求。好吧,因为如果在 Collection 视图上调用 reloadData,搜索栏就会被清除。

以上是关于以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局的屏幕外 UIView(以编程方式)

以编程方式将子视图添加到 UICollectionView

如何使用自动布局(约束)将子视图添加到 UIPageViewController?

以编程方式将自动布局添加到肋骨中添加的现有自动布局视图

自动布局和编程约束:如何处理多次触发的 updateConstraints?

什么方法以编程方式将子视图添加到 NIB