Objective c 如何以编程方式安装浮动布局约束

Objective c 如何以编程方式安装浮动布局约束,objective-c,uiscrollview,autolayout,Objective C,Uiscrollview,Autolayout,根据苹果公司的说法,我们可以在滚动视图中创建浮动视图,方法是在滚动视图之外添加约束 : 请注意,您可以使滚动视图的子视图显示为浮动 (不滚动)通过创建约束覆盖其他滚动内容 在视图和滚动视图子树外的视图之间,例如 滚动视图的superview : 在滚动视图中创建锚定视图 您可能会发现,您希望在滚动视图中创建一个区域,当用户滚动滚动视图的内容时,该区域不会移动。您可以通过使用单独的容器视图来实现这一点 当在滚动视图之前创建约束时(例如,通过界面生成器),这非常有效,但如果在滚动视图之后尝试创建所述

根据苹果公司的说法,我们可以在滚动视图中创建浮动视图,方法是在滚动视图之外添加约束

:

请注意,您可以使滚动视图的子视图显示为浮动 (不滚动)通过创建约束覆盖其他滚动内容 在视图和滚动视图子树外的视图之间,例如 滚动视图的superview

:

在滚动视图中创建锚定视图
您可能会发现,您希望在滚动视图中创建一个区域,当用户滚动滚动视图的内容时,该区域不会移动。您可以通过使用单独的容器视图来实现这一点

当在滚动视图之前创建约束时(例如,通过界面生成器),这非常有效,但如果在滚动视图之后尝试创建所述约束,则会得到位置不正确的视图

即使在滚动视图之后,如何以编程方式创建此锚定或浮动约束


我正在使用以下代码安装约束:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.pinkView
                                                              attribute:NSLayoutAttributeBottom
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.scrollViewContainer
                                                              attribute:NSLayoutAttributeBottom
                                                             multiplier:1
                                                               constant:0];
[self.scrollViewContainer addConstraint:constraint];
这就是我想要它的样子:

(请注意粉红色视图如何与青色视图垂直对齐。)

但是,如果用户滚动并点击按钮,则结果如下:


TLDR:浮动约束的特殊之处在于,它们在滚动滚动视图时不断更新其常量属性。因此,在创建约束时,必须通过预填充常量以等于滚动视图的内容偏移值来确保该约束与滚动视图同步


在最简单的例子中,假设我们有一个带有按钮的滚动视图。点击按钮时,滚动视图中应出现浮动视图

如果用户在点击按钮前滚动,浮动视图将无法正确对齐

问题是,当您通过约束创建浮动视图时,您正在创建一个特殊约束,该约束将在滚动视图滚动时不断更新其常量值。(其他约束不会随着对象的移动而更新其常量值。)最初创建约束时,常量值初始化为0,因此不知道到目前为止滚动视图发生了什么。Auto layout没有机会与scroll视图同步,因为它以前没有安装,因此Auto layout无法了解它

在滚动之前安装约束时,它起作用的原因是它安装在0,然后自动布局会自动为您更新其常量。因此,您“意外”安装了约束并将其与滚动视图同步(因为偏移从0开始)

通过覆盖scrollViewDidScroll:,我们可以看到此自动更新常量的证据:

Constraint constant: 95.00
Constraint constant: 98.50
Constraint constant: 101.50
Constraint constant: 105.50
Constraint constant: 106.50
解决方案是安装constant属性设置为当前滚动视图偏移的约束:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.pinkView
                                                              attribute:NSLayoutAttributeBottom
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.scrollViewContainer
                                                              attribute:NSLayoutAttributeBottom
                                                             multiplier:1
                                                               constant:self.scrollView.contentOffset.y];
[self.scrollViewContainer addConstraint:constraint];
其他值得注意的有趣事情:

  • 如果尝试在视图上安装具有0常量的约束,并且视图控制器具有导航栏,则该约束将失败,因为滚动视图的位置已移动到64,这与0不同

另一种思考方式是:


自动布局是愚蠢的。除了相对于滚动视图的相对值外,无法将浮动视图的位置设置为其他任何值。因此,苹果能够通过做一些棘手的事情来伪造这种效果:通过所有涉及浮动视图的约束,并不断更新其常量属性以反映滚动视图的内容偏移量。

另一种选择是将滚动视图改为UICollectionView,并将浮动视图改为补充视图。然后通过实现
layouttributesforelementsinrect:

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray *mutableAttributes = [layoutAttributes mutableCopy];

    UICollectionViewLayoutAttributes *floatingViewAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:@"my floating view" withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
    CGFloat floatingViewY = (self.collectionView.frame.size.height - floatingViewHeight) + self.collectionView.contentOffset.y; 
    CGRect frame = CGRectMake(floatingViewX, floatingViewY, floatingViewWidth, floatingViewHeight);
    floatingViewAttributes.frame = frame;
    floatingViewAttributes.zIndex = someLargePostiveInteger;

    [mutableAttributes addObject:floatingViewAttributes];

    return mutableAttributes;
}

UICollectionView
可能不适合您的应用程序,但我认为可能会将其丢弃。

如果视图浮动在滚动视图上方,为什么不将其添加到滚动视图的父视图中?@scottberrevotes:您希望将视图放置在滚动视图中有几个原因。其中一个问题是,您希望滚动视图的滚动条显示在此视图上方。好的,我没有想到这一点。我很想了解将它添加到scrollview而不是其父视图的其他动机。