带有分页的 UIScrollView 的约束
Posted
技术标签:
【中文标题】带有分页的 UIScrollView 的约束【英文标题】:Constraints on UIScrollView with paging 【发布时间】:2015-01-10 15:31:49 【问题描述】:我有覆盖整个屏幕的UIScrollView
,在其中我有 3 个并排的UIView
对象,通过分页管理。我想做出正确的限制,以便它也适合 iPhone 6。
拖动时是这样的:
UIScrollView
的约束运行良好,但是如何安排 UIScrollView
内部视图的约束?
提前致谢!!
【问题讨论】:
【参考方案1】:您的滚动视图的子视图需要两组约束。
第一组是规定滚动视图的滚动行为(即滚动视图的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 之前,我们没有 contentLayoutGuide
和 frameLayoutGuide
。因此,当您在滚动视图及其子视图之间设置约束时,它的行为类似于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 及更高版本,请使用更直观的 contentLayoutGuide
和 frameLayoutGuide
。
【讨论】:
您好,感谢您的快速答复。我试过这个,我得到的是“无法同时满足约束。可能以下列表中的至少一个约束是你不想要的。”具有指定约束的模拟器如下所示:up413.siz.co.il/up1/wj5miltomvny.png 谢谢! 这通常是由于未能为其中一个视图调用setTranslatesAutoresizingMaskIntoConstraints
造成的。或者,如果您在 IB 中向场景添加了一个视图,并在那里添加了一些约束以及我在上面以编程方式添加的约束,就会发生这种情况。底线,错误是说你有太多的约束,他们不能都得到满足。你必须找到多余的约束,并消除它。但是我知道如果我运行上面的代码,没有在 IB 中添加任何内容,它工作正常,所以我不能告诉你哪些约束是冲突的。
实际上,当我在不触及情节提要的情况下运行它时它确实有效,但很奇怪,当我从情节提要创建滚动视图和其他视图并从中制作 IBOutlets 时,没有添加任何约束故事板,它不起作用。你知道为什么会这样吗?
是的,在 IB 中,在“约束”下它说“选定的视图没有约束。在构建时,将为视图生成显式的左侧、顶部、宽度和高度约束。”底线,如果你不定义约束,它会为你做到这一点。事实上,如果您使用添加到 Storyboard 上的视图运行此程序,您会看到 NSIBPrototypingLayoutConstraint
类型的冲突约束。因此,要么(a)在 IB 中实现我的答案中的所有约束,以防止这些系统生成的约束;或 (b) 在添加新约束之前以编程方式删除这些约束。
非常感谢!你永远不会知道这有多大帮助!顺便说一句,在我看到您对 Swift 和 Xcode 的丰富知识之后,我想知道您是否可以在这里知道我的问题的答案:***.com/questions/27848510/… 谢谢!!!1【参考方案2】:
我需要通过向 ScrollView 添加视图来创建教程页面,但最终在正确安排视图方面遇到了问题。我正在使用 loadNibNamed
从 xib 创建视图,当我在 iPhone6 和 6plus 中运行应用程序时,我没有得到正确的帧,子视图的帧总是 320。所以我尝试了纯自动布局。因为我有很多视图要添加,所以我使用了一个视图数组,然后创建了一个 VFL 字符串,然后添加到滚动视图中,它就可以工作了。这是我创建的示例,它为我完成了工作
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
【讨论】:
以上是关于带有分页的 UIScrollView 的约束的主要内容,如果未能解决你的问题,请参考以下文章
将带有分页的 UIScrollView 添加到现有的 UIViewController