以编程方式使用自动布局分页 UIScrollView?

Posted

技术标签:

【中文标题】以编程方式使用自动布局分页 UIScrollView?【英文标题】:Paging UIScrollView with autolayout programmatically? 【发布时间】:2016-05-26 17:46:03 【问题描述】:

我正在尝试复制重现此问题的答案:UIScrollView Paging Autolayout & Storyboard

以编程方式而不是使用界面生成器。

我遇到了一些约束冲突,我不知道为什么?

- (void)viewDidLoad 
[super viewDidLoad];

// self.view is always the size of the application window
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor blackColor];

self.dummyView = [[UIView alloc] init];
self.dummyView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.dummyView];

self.scrollView = [[UIScrollView alloc] init];
self.scrollView.backgroundColor = [UIColor blueColor];
[self.dummyView addSubview:self.scrollView];

self.contentView = [[UIView alloc] init];
self.contentView.backgroundColor = [UIColor orangeColor];
[self.scrollView addSubview:self.contentView];

self.pageView = [[UIView alloc] init];
self.pageView.backgroundColor = [UIColor yellowColor];
[self.contentView addSubview:self.pageView];

self.pageView2 = [[UIView alloc] init];
self.pageView2.backgroundColor = [UIColor greenColor];
[self.contentView addSubview:self.pageView2];

self.pageView3 = [[UIView alloc] init];
self.pageView3.backgroundColor = [UIColor purpleColor];
[self.contentView addSubview:self.pageView3];

// constraints must be added after the view heirarchy is established
[self addConstraints];



- (void) addConstraints 

    // Tell autoLayout to use my constraints (as opposed to inventing its own)
    self.view.translatesAutoresizingMaskIntoConstraints = NO;


    // ****  Dummy View constraints:

    // dummyView.leading = view.leading
    NSLayoutConstraint* myConstraint = [NSLayoutConstraint
                    constraintWithItem:self.dummyView
                    attribute:NSLayoutAttributeLeading
                    relatedBy:NSLayoutRelationEqual
                    toItem:self.view
                    attribute:NSLayoutAttributeLeading
                    multiplier:1.0
                    constant:0];
    myConstraint.identifier = @"dummyView.leading = view.leading";
    [self.view addConstraint:myConstraint];

    // dummyView.trailing = view.trailing
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.dummyView
                   attribute:NSLayoutAttributeTrailing
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.view
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"dummyView.trailing = view.trailing";
    [self.view addConstraint:myConstraint];

    // dummyView.top = view.top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.dummyView
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.view
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"dummyView.top = view.top";
    [self.view addConstraint:myConstraint];

    // dummyView.bottom = view.bottom
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.dummyView
                   attribute:NSLayoutAttributeBottom
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.view
                   attribute:NSLayoutAttributeBottom
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"dummyView.bottom = view.bottom";
    [self.view addConstraint:myConstraint];


    // **** Scroll View constraints

    // scrollView.trailing = dummyView.trailing
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.scrollView
                   attribute:NSLayoutAttributeTrailing
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"scrollView.trailing = dummyView.trailing";
    [self.dummyView addConstraint:myConstraint];

    // scrollView.leading = dummyView.leading
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.scrollView
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeLeading
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"scrollView.leading = dummyView.leading";
    [self.dummyView addConstraint:myConstraint];

    // scrollView.Top = dummyView.top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.scrollView
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"scrollView.Top = dummyView.top";
    [self.dummyView addConstraint:myConstraint];

    // scrollView.bottom = dummyView.bottom
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.scrollView
                   attribute:NSLayoutAttributeBottom
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeBottom
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"scrollView.bottom = dummyView.bottom";
    [self.dummyView addConstraint:myConstraint];





    // **** Content View Constraints


    // contentView.width = dummyView.width * 3
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeWidth
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeWidth
                   multiplier:3.0
                   constant:0];
    myConstraint.identifier = @"contentView.width = dummyView.width * 3";
    [self.dummyView addConstraint:myConstraint];

    // contentView.height = dummyView.height
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeHeight
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeHeight
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"contentView.height = dummyView.height";
    [self.dummyView addConstraint:myConstraint];

    // contentView.leading = scrollView.leading
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.scrollView
                   attribute:NSLayoutAttributeLeading
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"contentView.leading = scrollView.leading";
    [self.scrollView addConstraint:myConstraint];

    // contentView.trailing = scrollView.trailing
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeTrailing
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.scrollView
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"contentView.trailing = scrollView.trailing";
    [self.scrollView addConstraint:myConstraint];

    // contentView.Top = scrollView.top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.scrollView
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"contentView.Top = scrollView.top";
    [self.scrollView addConstraint:myConstraint];

    // contentView.bottom = scrollView.bottom
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.contentView
                   attribute:NSLayoutAttributeBottom
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.scrollView
                   attribute:NSLayoutAttributeBottom
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"contentView.bottom = scrollView.bottom";
    [self.scrollView addConstraint:myConstraint];




    // **** Page View 1 Constraints

    // pageView.leading = contentView.leading
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.contentView
                   attribute:NSLayoutAttributeLeading
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView.leading = contentView.leading";
    [self.contentView addConstraint:myConstraint];

    // pageView.top = contenentView.top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.contentView
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView.top = contenentView.top";
    [self.contentView addConstraint:myConstraint];

    // pageView.width = dummyView.width
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView
                   attribute:NSLayoutAttributeWidth
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeWidth
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView.width = dummyView.width";
    [self.dummyView addConstraint:myConstraint];


    // pageView.height = dummyView.height
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView
                   attribute:NSLayoutAttributeHeight
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.dummyView
                   attribute:NSLayoutAttributeHeight
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView.height = dummyView.height";
    [self.dummyView addConstraint:myConstraint];


    // **** Page View 2 Constraints

    // pageView2.height = pageView.height
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView2
                   attribute:NSLayoutAttributeHeight
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView2
                   attribute:NSLayoutAttributeHeight
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView2.height = pageView.height";
    [self.contentView addConstraint:myConstraint];

    // pageView2.width = pageView.width
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView2
                   attribute:NSLayoutAttributeWidth
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeWidth
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @" pageView2.width = pageView.width";
    [self.contentView addConstraint:myConstraint];

    // pageView2.top = pageView.top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView2
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView2.top = pageView.top";
    [self.contentView addConstraint:myConstraint];

    // pageView2.leading = pageView.trailing
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView2
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView2.leading = pageView.trailing";
    [self.contentView addConstraint:myConstraint];


    // **** Page View 3 Constraints

    // pageView3.height = pageView.height
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView3
                   attribute:NSLayoutAttributeHeight
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeHeight
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView3.height = pageView.height";
    [self.contentView addConstraint:myConstraint];

    // pageView3.width = pageView.width
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView3
                   attribute:NSLayoutAttributeWidth
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeWidth
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView3.width = pageView.width";
    [self.contentView addConstraint:myConstraint];

    // pageView3.Top = pageView.Top
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView3
                   attribute:NSLayoutAttributeTop
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView
                   attribute:NSLayoutAttributeTop
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView3.Top = pageView.Top";
    [self.contentView addConstraint:myConstraint];

    // pageView3.leading = pageView2.trailing
    myConstraint =[NSLayoutConstraint
                   constraintWithItem:self.pageView3
                   attribute:NSLayoutAttributeLeading
                   relatedBy:NSLayoutRelationEqual
                   toItem:self.pageView2
                   attribute:NSLayoutAttributeTrailing
                   multiplier:1.0
                   constant:0];
    myConstraint.identifier = @"pageView3.leading = pageView2.trailing";
    [self.contentView addConstraint:myConstraint];

错误是:

 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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x134e1c340 h=--& v=--& UIView:0x134e3e740.midX ==>",
    "<NSAutoresizingMaskLayoutConstraint:0x134d47a20 h=--- v=--- H:[UIWindow:0x134e3a6c0(375)]>",
    "<NSLayoutConstraint:0x134e4c960 H:|-(0)-[UIView:0x134e3bdf0](LTR)   (Names: '|':UIWindow:0x134e3a6c0 )>",
    "<NSLayoutConstraint:0x134e4ca00 UIView:0x134e3bdf0.right == UIWindow:0x134e3a6c0.right>",
    "<NSLayoutConstraint:0x134e3f150 'dummyView.leading = view.leading' H:|-(0)-[UIView:0x134e3cb00]   (Names: '|':UIView:0x134e3bdf0 )>",
    "<NSLayoutConstraint:0x134e3f480 'dummyView.trailing = view.trailing' UIView:0x134e3cb00.trailing == UIView:0x134e3bdf0.trailing>",
    "<NSLayoutConstraint:0x134e3fc60 'pageView.leading = contentView.leading' H:|-(0)-[UIView:0x134e3e740]   (Names: '|':UIView:0x134e3e450 )>",
    "<NSLayoutConstraint:0x134e3fd30 'pageView.width = dummyView.width' UIView:0x134e3e740.width == UIView:0x134e3cb00.width>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x134e3fc60 'pageView.leading = contentView.leading' H:|-(0)-[UIView:0x134e3e740]   (Names: '|':UIView:0x134e3e450 )>

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.
2016-05-26 10:28:55.062 autolayouttest[682:208278] 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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x134d3e930 h=--& v=--& UIView:0x134e3e740.midY ==>",
    "<NSAutoresizingMaskLayoutConstraint:0x134d45af0 h=--- v=--- V:[UIWindow:0x134e3a6c0(667)]>",
    "<NSLayoutConstraint:0x134e4c910 V:|-(0)-[UIView:0x134e3bdf0]   (Names: '|':UIWindow:0x134e3a6c0 )>",
    "<NSLayoutConstraint:0x134e4c9b0 UIView:0x134e3bdf0.bottom == UIWindow:0x134e3a6c0.bottom>",
    "<NSLayoutConstraint:0x134e3f540 'dummyView.bottom = view.bottom' UIView:0x134e3cb00.bottom == UIView:0x134e3bdf0.bottom>",
    "<NSLayoutConstraint:0x134e3f4d0 'dummyView.top = view.top' V:|-(0)-[UIView:0x134e3cb00]   (Names: '|':UIView:0x134e3bdf0 )>",
    "<NSLayoutConstraint:0x134e3f9c0 'pageView.height = dummyView.height' UIView:0x134e3e740.height == UIView:0x134e3cb00.height>",
    "<NSLayoutConstraint:0x134e3fce0 'pageView.top = contenentView.top' V:|-(0)-[UIView:0x134e3e740]   (Names: '|':UIView:0x134e3e450 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x134e3fce0 'pageView.top = contenentView.top' V:|-(0)-[UIView:0x134e3e740]   (Names: '|':UIView:0x134e3e450 )>

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.

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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x134d47a20 h=--- v=--- H:[UIWindow:0x134e3a6c0(375)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x134d476e0 h=--& v=--& UIScrollView:0x135000000.midX ==>",
    "<NSLayoutConstraint:0x134e4c960 H:|-(0)-[UIView:0x134e3bdf0](LTR)   (Names: '|':UIWindow:0x134e3a6c0 )>",
    "<NSLayoutConstraint:0x134e4ca00 UIView:0x134e3bdf0.right == UIWindow:0x134e3a6c0.right>",
    "<NSLayoutConstraint:0x134e3f150 'dummyView.leading = view.leading' H:|-(0)>",
    "<NSLayoutConstraint:0x134e3f480 'dummyView.trailing = view.trailing' UIView:0x134e3cb00.trailing == UIView:0x134e3bdf0.trailing>",
    "<NSLayoutConstraint:0x134e3f610 'scrollView.leading = dummyView.leading' H:|-(0)-[UIScrollView:0x135000000]   (Names: '|':UIView:0x134e3cb00 )>",
    "<NSLayoutConstraint:0x134e3f590 'scrollView.trailing = dummyView.trailing' UIScrollView:0x135000000.trailing == UIView:0x134e3cb00.trailing>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x134e3f590 'scrollView.trailing = dummyView.trailing' UIScrollView:0x135000000.trailing == UIView:0x134e3cb00.trailing>

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.
2016-05-26 10:28:55.067 autolayouttest[682:208278] 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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x134d47a20 h=--- v=--- H:[UIWindow:0x134e3a6c0(375)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x134d43660 h=--& v=--& UIView:0x134e3cb00.midX ==>",
    "<NSLayoutConstraint:0x134e4c960 H:|-(0)-[UIView:0x134e3bdf0](LTR)   (Names: '|':UIWindow:0x134e3a6c0 )>",
    "<NSLayoutConstraint:0x134e4ca00 UIView:0x134e3bdf0.right == UIWindow:0x134e3a6c0.right>",
    "<NSLayoutConstraint:0x134e3f150 'dummyView.leading = view.leading' H:|-(0)-[UIView:0x134e3cb00]   (Names: '|':UIView:0x134e3bdf0 )>",
    "<NSLayoutConstraint:0x134e3f480 'dummyView.trailing = view.trailing' UIView:0x134e3cb00.trailing == UIView:0x134e3bdf0.trailing>"

如有任何帮助,我们将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

// 告诉 autoLayout 使用我的约束(而不是发明它的 自己的) self.view.translatesAutoresizingMaskIntoConstraints = NO;

必须对所有以编程方式创建的视图执行此操作。由于您尚未创建 self.view,因此不应为此视图更改 translatesAutoresizingMaskIntoConstraints

// Tell autoLayout to use my constraints (as opposed to inventing its own)
    self.dummyView.translatesAutoresizingMaskIntoConstraints = NO;
    self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
    self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    self.pageView.translatesAutoresizingMaskIntoConstraints = NO;
    self.pageView2.translatesAutoresizingMaskIntoConstraints = NO;
    self.pageView3.translatesAutoresizingMaskIntoConstraints = NO;

【讨论】:

以上是关于以编程方式使用自动布局分页 UIScrollView?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自动布局以编程方式创建 UITableView?

如何以编程方式添加标签并以编程方式使用自动布局定位它

使用自动布局(以编程方式)水平对齐 UIButton

使用自动布局以编程方式添加背景图像视图

以编程方式使用自动布局的 3 个等高视图

调整大小后使用自动布局以编程方式居中 UIImageVIew