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]];

这应该会给你一些指导,那里可能还有其他错误,但修复这些错误是一个很好的起点。