UIScrollView在iOS 8 / Xcode 6 GM Seed上使用自动布局大小时会出现问题

7

如何使用自动布局计算内容大小以使滚动视图正常工作?

Xcode 6会在存在带有自动布局的滚动视图时创建“UIView Encapsulated Layout Height”约束,此约束将强制设置高度为框架高度(从而使滚动视图的滚动功能无效)。

布局错误 - iPhone 5s模拟器在Xcode 6 GM Seed中

错误:

2014-09-09 21:06:01.059 ScrollViewLayoutBreaking[24488:88731] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f9a19ebd150 V:[UIView:0x7f9a19ea7f90(530)]>",
    "<NSLayoutConstraint:0x7f9a19ec1370 V:[UIView:0x7f9a19ebd5e0(110)]>",
    "<NSLayoutConstraint:0x7f9a19ea9ee0 V:[_UILayoutGuide:0x7f9a19ec18d0]-(0)-[UIView:0x7f9a19ea7f90]>",
    "<NSLayoutConstraint:0x7f9a19ec1fa0 V:[UIView:0x7f9a19ea7f90]-(0)-[UIView:0x7f9a19ebd5e0]>",
    "<NSLayoutConstraint:0x7f9a19e8d270 V:[UIView:0x7f9a19ebd5e0]-(5)-[_UILayoutGuide:0x7f9a19ec2260]>",
    "<_UILayoutSupportConstraint:0x7f9a19ea0ac0 V:[_UILayoutGuide:0x7f9a19ec18d0(0)]>",
    "<_UILayoutSupportConstraint:0x7f9a19ea7380 V:|-(0)-[_UILayoutGuide:0x7f9a19ec18d0]   (Names: '|':UIScrollView:0x7f9a19ea76a0 )>",
    "<_UILayoutSupportConstraint:0x7f9a19e21d00 V:[_UILayoutGuide:0x7f9a19ec2260(0)]>",
    "<_UILayoutSupportConstraint:0x7f9a19e8a930 _UILayoutGuide:0x7f9a19ec2260.bottom == UIScrollView:0x7f9a19ea76a0.bottom>",
    "<NSLayoutConstraint:0x7f9a1c003f50 'UIView-Encapsulated-Layout-Height' V:[UIScrollView:0x7f9a19ea76a0(504)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f9a19ebd150 V:[UIView:0x7f9a19ea7f90(530)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

编辑:此滚动视图中的所有视图都已进行自动布局,并已固定到滚动视图的顶部和底部以及两侧。我知道如果未在所有四个边缘上绑定它,则无法创建内容大小。iOS 7 / XCode 5中的自动布局和滚动是正确的,但完全相同的代码和故事板在iOS 8 / XCode 6中出现错误。


将问题重新表述以使其更简洁明了。目前正在使用Xcode 6 GM Seed版本。 - Uzaak
我能想到的最好的方法是使用一个带有单个自动调整大小单元格的表视图,该单元格将充当滚动视图,分隔符样式为无。但这对我来说已经够糟糕了,只能作为绝对的最后手段。 - Uzaak
为什么这个被关闭了?这是一个有效的问题。 - Alex B
你能更明确地说明约束是从哪里到哪里,以及框架是什么吗?如果这只是一个一般性的问题,那么有很多例子和帖子,但是你必须将内容视图的边缘设置为父滚动视图的边缘,并从内容视图到滚动视图设置相等的宽度和高度约束。这样做将导致当内容视图超出父滚动视图的大小时出现滚动内容视图。自动布局是一个“难点”,但是一旦掌握就可以使用。你可以在IB中完成所有这些操作。 - Chris Conover
4个回答

0

从您的截图来看,我猜测您正在使用滚动视图中的自定义视图,因此...

您的内容视图是:STH、Foo、Bar、Baz、Qux、Blah、Woot、Lorem、Ipsum、Dolor

在代码中,您可以通过将所有内容视图相互关联(除了顶部和底部视图,这些必须与滚动视图的边缘相关联)来自动设置内容大小,使用自动布局。以下是一个示例:

-(void)example{

UIView *parentView; //Can be the Scroll View or the Scroll View superview, it's better for the ScrollView to be the Owner of the restrictions
UIView *previousView;
UIScrollView *scrollView;

NSArray * arrayOfContentViews = @[STH,Foo,Bar,Baz,Qux,Blah,Woot,Lorem,Ipsum,Dolor];

for (UIView * currentView in arrayOfContentViews) {

    //Important for Autolayout Restrictions
    currentView.translateAutoresizingMask = NO;
    [scrollview addSubview:currentView];

    if (previousView == nil) {
        //For the Top, Left and Right Attribute Edges of the ScrollView
        previousView = scrollView;

        [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                               attribute:NSLayoutAttributeTop
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:previousView
                                                               attribute:NSLayoutAttributeTop
                                                              multiplier:1.0
                                                                constant:0.0]];

        //10% of the scrollview Frame Size (not Content Size)
        [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                               attribute:NSLayoutAttributeHeight
                                                               relatedBy:NSLayoutRelationGreaterThanOrEqual
                                                                  toItem:previousView
                                                               attribute:NSLayoutAttributeHeight
                                                              multiplier:0.1
                                                                constant:0.0]];            

    }else{

        [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                               attribute:NSLayoutAttributeTop
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:previousView
                                                               attribute:NSLayoutAttributeBottom
                                                              multiplier:1.0
                                                                constant:0.0]];

        [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                               attribute:NSLayoutAttributeHeight
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:previousView
                                                               attribute:NSLayoutAttributeHeight
                                                              multiplier:1.0
                                                                constant:0.0]];
    }

    [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                           attribute:NSLayoutAttributeLeft
                                                           relatedBy:NSLayoutRelationEqual
                                                              toItem:previousView
                                                           attribute:NSLayoutAttributeLeft
                                                          multiplier:1.0
                                                            constant:0.0]];

    [parentView addConstraint:[NSLayoutConstraint constraintWithItem:currentView
                                                           attribute:NSLayoutAttributeRight
                                                           relatedBy:NSLayoutRelationEqual
                                                              toItem:previousView
                                                           attribute:NSLayoutAttributeRight
                                                          multiplier:1.0
                                                            constant:0.0]];


    previousView = currentView;

    }

//Last View Dolor to the Bottom Edge of the scrollView
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:previousView
                                                       attribute:NSLayoutAttributeBottom
                                                       relatedBy:NSLayoutRelationEqual
                                                          toItem:scrollView
                                                       attribute:NSLayoutAttributeBottom
                                                      multiplier:1.0
                                                        constant:0.0]];
}

0

为了使UIScrollView在垂直方向上正常工作,需要将子视图从顶部到底部按顺序链接。

如果设置其子视图的顶部/底部边距,则无法确定滚动视图如何在垂直方向上呈现自身,因为它根据内容计算自己的高度。

因此,您应该允许滚动视图独立于其子项确定其自己的高度。

因此,将您的滚动视图作为另一个视图的子视图添加,并具有与该视图相关联的约束条件,然后您可以相对于滚动视图自由地添加子项。


0

我觉得我应该回答这个问题,因为它一直收到回复。

代码已经正确地自动布局。如问题所述,相同的代码在使用Xcode 5和iOS 7时产生了完美的、没有警告/错误的滚动视图,并且在Xcode 6 GM Seed和iOS 8中会破坏我没有手动创建的布局约束。

看起来这是一个Xcode 6 GM Seed的bug,实际上,在第一次发布后的Xcode 6未来更新中,相同的代码可以无缝运行,而不会破坏任何约束。


0

如果您正在使用IB,则选择UIViewController并从底部的AutoLayout菜单中选择删除所有约束。然后选择添加缺少的约束。这将解决您的问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接