scrollView:如何创建带分页的纯自动布局滚动视图?
scrollView: how to create a pure auto layout scrollview with paging?
谁能告诉我我做错了什么...
- 将 UIScrollView 固定到它的容器视图
- 将所有子视图固定到 UIScrollView
在阅读了Apple TechNote 之后,我尝试了混合方法和纯自动布局方法。使用 NIB 的混合方法对分页效果很糟糕,在滚动视图中看起来像一张大图片,而不是分页。
然后我在代码中创建了纯自动布局版本,UIScrollView 作为 UIView 的子视图。这次视图卡住了,而且 UIImage 很大,就像它的全尺寸一样:
//scroll view
if (self.scrollView == nil)
{
self.scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView setClipsToBounds:NO];
[self.scrollView setPagingEnabled:YES];
[self addSubview: self.scrollView];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView(300)]|"
options:0 metrics:nil
views:@{@"scrollView":self.scrollView}]];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView(300)]|"
options:0 metrics:nil
views:@{@"scrollView":self.scrollView}]];
-(void) createContentView
{
for (int i=0; i<self.pageImages.count; i++) {
UILabel* topLabel = [[UILabel alloc] init];
topLabel.text = [NSString stringWithFormat:@"topLabel %d", i+1];
[topLabel sizeToFit];
[self.topLabelArray insertObject:topLabel atIndex:i];
[self.scrollView addSubview:topLabel];
topLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* bottomLabel = [[UILabel alloc] init];
bottomLabel.text = [NSString stringWithFormat:@"bottomLabel %d", i+1];
[bottomLabel sizeToFit];
[self.bottomLabelArray insertObject:bottomLabel atIndex:i];
[self.scrollView addSubview:bottomLabel];
bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
UIButton* button = [[UIButton alloc] init];
button.titleLabel.text = [NSString stringWithFormat:@"button %d", i+1];
[button sizeToFit];
[self.buttonArray insertObject:button atIndex:i];
[self.scrollView addSubview:button];
button.translatesAutoresizingMaskIntoConstraints = NO;
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.pageViews insertObject:imageView atIndex:i];
[self.scrollView addSubview:imageView];
NSDictionary* viewsDictionary = @{@"topLabel":topLabel,
@"bottomLabel":bottomLabel,
@"button": button,
@"imageView": imageView
};
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[topLabel]-(10)-[imageView]-(10)-[bottomLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
if (i==0)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[topLabel]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[imageView]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:viewsDictionary]];
}
else if (i == self.pageImages.count)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
}
else
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevTopLabel]-(10)-[topLabel]"
options:0 metrics:nil
views:@{@"prevTopLabel": [self.topLabelArray objectAtIndex: i-1],
@"topLabel": topLabel
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevImageView]-(10)-[imageView]"
options:0 metrics:nil
views:@{@"prevImageView": [self.pageViews objectAtIndex: i-1],
@"imageView": imageView
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevButton]-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:@{@"prevButton": [self.buttonArray objectAtIndex: i-1],
@"button":button,
@"bottomLabel": bottomLabel
}]];
}
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:topLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.0]];
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:bottomLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:0.8
constant:0.0]];
// [self.scrollView addConstraint:[NSLayoutConstraint
//
好的,这里有一些错误:
else if (i == self.pageImages.count)
此子句永远不会 运行,因为您的循环计数设置为在 i == self.pageImages.count -1
时中断,此处为 for (int i=0; i<self.pageImages.count; i++)
。
下一个
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
这些也会产生无效的约束,特别是 @"H:-(10)-[bottomLabel]....
不会将最左边的约束固定到任何东西上。所有连接视图的视觉格式字符串都需要以视图开始或结束。子视图 ([subview]
) 或父视图 (|
)。要解决此问题,您需要在循环中保留对前一页标签的引用,并将其添加到 VFL 字符串的开头。像这样
@"H:[prevBottomLabel]-(10)-[bottomLabel]....
prevBottomLabel = bottomLabel;
// Continue loop
下一个:
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
这不会有预期的效果,因为您不能手动设置框架,然后打开自动布局。目前,框架值被忽略,高度和宽度由图像视图的固有内容大小设置,这将是图像的高度和宽度。如果要设置高和宽,需要有constraints,如下:
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
这应该会给你一些指导,那里可能还有其他错误,但修复这些错误是一个很好的起点。
谁能告诉我我做错了什么... - 将 UIScrollView 固定到它的容器视图 - 将所有子视图固定到 UIScrollView
在阅读了Apple TechNote 之后,我尝试了混合方法和纯自动布局方法。使用 NIB 的混合方法对分页效果很糟糕,在滚动视图中看起来像一张大图片,而不是分页。
然后我在代码中创建了纯自动布局版本,UIScrollView 作为 UIView 的子视图。这次视图卡住了,而且 UIImage 很大,就像它的全尺寸一样:
//scroll view
if (self.scrollView == nil)
{
self.scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView setClipsToBounds:NO];
[self.scrollView setPagingEnabled:YES];
[self addSubview: self.scrollView];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView(300)]|"
options:0 metrics:nil
views:@{@"scrollView":self.scrollView}]];
[self addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView(300)]|"
options:0 metrics:nil
views:@{@"scrollView":self.scrollView}]];
-(void) createContentView
{
for (int i=0; i<self.pageImages.count; i++) {
UILabel* topLabel = [[UILabel alloc] init];
topLabel.text = [NSString stringWithFormat:@"topLabel %d", i+1];
[topLabel sizeToFit];
[self.topLabelArray insertObject:topLabel atIndex:i];
[self.scrollView addSubview:topLabel];
topLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* bottomLabel = [[UILabel alloc] init];
bottomLabel.text = [NSString stringWithFormat:@"bottomLabel %d", i+1];
[bottomLabel sizeToFit];
[self.bottomLabelArray insertObject:bottomLabel atIndex:i];
[self.scrollView addSubview:bottomLabel];
bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
UIButton* button = [[UIButton alloc] init];
button.titleLabel.text = [NSString stringWithFormat:@"button %d", i+1];
[button sizeToFit];
[self.buttonArray insertObject:button atIndex:i];
[self.scrollView addSubview:button];
button.translatesAutoresizingMaskIntoConstraints = NO;
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.pageViews insertObject:imageView atIndex:i];
[self.scrollView addSubview:imageView];
NSDictionary* viewsDictionary = @{@"topLabel":topLabel,
@"bottomLabel":bottomLabel,
@"button": button,
@"imageView": imageView
};
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[topLabel]-(10)-[imageView]-(10)-[bottomLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
if (i==0)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[topLabel]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[imageView]"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:viewsDictionary]];
}
else if (i == self.pageImages.count)
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
}
else
{
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevTopLabel]-(10)-[topLabel]"
options:0 metrics:nil
views:@{@"prevTopLabel": [self.topLabelArray objectAtIndex: i-1],
@"topLabel": topLabel
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevImageView]-(10)-[imageView]"
options:0 metrics:nil
views:@{@"prevImageView": [self.pageViews objectAtIndex: i-1],
@"imageView": imageView
}]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[prevButton]-(10)-[bottomLabel]-(10)-[button]"
options:0 metrics:nil
views:@{@"prevButton": [self.buttonArray objectAtIndex: i-1],
@"button":button,
@"bottomLabel": bottomLabel
}]];
}
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:topLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.0]];
[self.scrollView addConstraint:[NSLayoutConstraint
constraintWithItem:bottomLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imageView
attribute:NSLayoutAttributeCenterX
multiplier:0.8
constant:0.0]];
// [self.scrollView addConstraint:[NSLayoutConstraint
//
好的,这里有一些错误:
else if (i == self.pageImages.count)
此子句永远不会 运行,因为您的循环计数设置为在 i == self.pageImages.count -1
时中断,此处为 for (int i=0; i<self.pageImages.count; i++)
。
下一个
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[topLabel]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[imageView]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
[self.scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:-(10)-[bottomLabel]-(10)-[button]-(10)-|"
options:0 metrics:nil
views:viewsDictionary]];
这些也会产生无效的约束,特别是 @"H:-(10)-[bottomLabel]....
不会将最左边的约束固定到任何东西上。所有连接视图的视觉格式字符串都需要以视图开始或结束。子视图 ([subview]
) 或父视图 (|
)。要解决此问题,您需要在循环中保留对前一页标签的引用,并将其添加到 VFL 字符串的开头。像这样
@"H:[prevBottomLabel]-(10)-[bottomLabel]....
prevBottomLabel = bottomLabel;
// Continue loop
下一个:
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.pageImages objectAtIndex:i]]];
imageView.frame = CGRectMake(0,0,200,200);
imageView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.contentMode = UIViewContentModeScaleAspectFit;
这不会有预期的效果,因为您不能手动设置框架,然后打开自动布局。目前,框架值被忽略,高度和宽度由图像视图的固有内容大小设置,这将是图像的高度和宽度。如果要设置高和宽,需要有constraints,如下:
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
[imageView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[imageView(200)]"
options:0 metrics:nil
views:viewsDictionary]];
这应该会给你一些指导,那里可能还有其他错误,但修复这些错误是一个很好的起点。