对带有分页的 UIScrollView 的约束

Constraints on UIScrollView with paging

我有 UIScrollView 覆盖整个屏幕,里面有 3 UIView 个对象 side-by-side,通过分页管理。我想做出正确的约束,以便它也适合 iPhone 6。

拖动时是这样的:

UIScrollView 的约束运行良好,但如何安排 UIScrollView 内视图的约束?

提前致谢!!

您的滚动视图的子视图需要两组约束。

  • 第一组是规定滚动视图的滚动行为(即滚动视图的 contentSize 是什么)。为此,我们使用滚动视图的 contentLayoutGuide。请注意,与大多数约束不同,这并不规定子视图的大小,而只是规定这些子视图与滚动视图的 contentSize.

  • 之间的关系
  • 第二组是子视图大小的约束。为此,我们使用滚动视图的 frameLayoutGuide.

因此,假设您有三个子视图,分别是红色、绿色和蓝色,您可以这样做:

// Set horizontal constraints relative to scroll view contentLayoutGuide

NSLayoutConstraint.activate([
    redView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
    greenView.leadingAnchor.constraint(equalTo: redView.trailingAnchor),
    blueView.leadingAnchor.constraint(equalTo: greenView.trailingAnchor),
    blueView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
])

// set constraints that are common to all three subviews

for subview in [blueView, greenView, redView] {
    NSLayoutConstraint.activate([
        // Set vertical constraints to scroll view contentLayoutGuide

        subview.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
        subview.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),

        // Set width and height of subviews relative to scroll view's frame

        subview.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
        subview.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
    ])
}

以上假定您已关闭这三个子视图的 translatesAuthresizingMaskIntoConstraints。但希望以上说明了这个想法。

顺便说一句,你也可以在IB中完成这一切(参考“内容布局指南”和“框架布局指南”,就像上面一样)。我只是在此处以编程方式完成,因此您可以确切地看到发生了什么。


在 iOS 11 之前,我们没有 contentLayoutGuideframeLayoutGuide。因此,当您在滚动视图及其子视图之间设置约束时,它的行为类似于 contentLayoutGuide (即仅影响 contentSize 和子视图的关系)并设置子视图的实际大小,您有到达滚动视图的超级视图:

// Set horizontal constraints relative to scroll view contentSize

NSLayoutConstraint.activate([
    redView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
    greenView.leadingAnchor.constraint(equalTo: redView.trailingAnchor),
    blueView.leadingAnchor.constraint(equalTo: greenView.trailingAnchor),
    blueView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
])

// set constraints that are common to all three subviews

for subview in [blueView, greenView, redView] {
    NSLayoutConstraint.activate([
        // Set vertical constraints to scroll view contentSize

        subview.topAnchor.constraint(equalTo: scrollView.topAnchor),
        subview.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),

        // Set width and height of subviews relative to superview

        subview.widthAnchor.constraint(equalTo: view.widthAnchor),
        subView.heightAnchor.constraint(equalTo: view.heightAnchor),
    ])
}

顺便说一下,Apple 在 Technical Note TN 2154 中讨论了此行为。

但如果针对 iOS 11 及更高版本,请使用更直观的 contentLayoutGuideframeLayoutGuide

我需要通过向 ScrollView 添加视图来创建教程页面,但我最终在正确排列视图方面遇到了问题。我使用 loadNibNamed 从 xib 创建视图,当我是 运行 iPhone6 和 6plus 中的应用程序时,我没有得到正确的框架,子视图的框架总是以 320 出现。所以我尝试了纯自动布局。因为我有很多视图要添加,所以我使用了一个视图数组,然后创建了一个 VFL 字符串,然后添加到 scrollview 并且它起作用了。这是我创建的示例,这对我有用

ScrollViewAutolayout

/*!

 Create an array of views that we need to load
 @param nil
 @result creates array of views and adds it to scrollview
 */
-(void)setUpViews
{
    [viewsDict setObject:contentScrollView forKey:@"parent"];
    int count = 20;//Lets layout 20 views
    for (int i=0; i<=count; i++) {
        // I am loading the view from xib.
        ContentView *contenView = [[NSBundle mainBundle] loadNibNamed:@"ContentView" owner:self options:nil][0];
        contenView.translatesAutoresizingMaskIntoConstraints = NO;
        // Layout the text and color
        [contenView layoutTheLabel];
        [contentScrollView addSubview:contenView];
        [viewsArray addObject:contenView];
    }
}
/*!
 Method to layout the childviews in the scrollview.
 @param nil
 @result layout the child views
 */
-(void)layoutViews
{
    NSMutableString *horizontalString = [NSMutableString string];
    // Keep the start of the horizontal constraint
    [horizontalString appendString:@"H:|"];
    for (int i=0; i<viewsArray.count; i++) {
        // Here I am providing the index of the array as the view name key in the dictionary
        [viewsDict setObject:viewsArray[i] forKey:[NSString stringWithFormat:@"v%d",i]];
        // Since we are having only one view vertically, then we need to add the constraint now itself. Since we need to have fullscreen, we are giving height equal to the superview.
        NSString *verticalString = [NSString stringWithFormat:@"V:|[%@(==parent)]|", [NSString stringWithFormat:@"v%d",i]];
        // add the constraint
        [contentScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalString options:0 metrics:nil views:viewsDict]];
        // Since we need to horizontally arrange, we construct a string, with all the views in array looped and here also we have fullwidth of superview.
        [horizontalString appendString:[NSString stringWithFormat:@"[%@(==parent)]", [NSString stringWithFormat:@"v%d",i]]];
    }
    // Close the string with the parent
    [horizontalString appendString:@"|"];
    // apply the constraint
    [contentScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:horizontalString options:0 metrics:nil views:viewsDict]];
}

更新 SWIFT 3 版本

使用上述代码的 Swift 3 版本添加了一个新的 repo。

ScrollViewAutoLayout