Search code examples
iosxcodeios6autolayout

Using Auto Layout to change spaces equally on resizing


If I have a view in my app with 3 subviews (as an example) with the following spacing between them:

TOP - 40 points - SUBVIEW 1 - 60 points - SUBVIEW 2 - 80 points - SUBVIEW 3 - 80 points - BOTTOM

I understand how I can use auto layout to ensure each of my subviews keeps it's height and width, and I can get everything to be aligned on either a 3.5 OR 4 inch iPhone screen.


But I can't work out what kind of constraint I need to make it so that if it were aligned for a 3.5" screen, and then went to a 4" screen, each spacing would increase proportionally (e.g. 40 points would go to 47, 60 to 71, 80 to 95 - or thereabouts).

Is this possible? Or do I need to make all the spacing equal between the elements? (If so how would I still get it to resize equally?)


I'm new to Auto Layout so if I've missed anything off, or haven't made it clear what I means please let me know, thank you.


Solution

  • I don't know any easy way to do this. I made one where all the spaces were equal, but to do that, I had to fill the spaces with invisible labels (just label with no title). So, I had my 4 visible objects and the 5 "spacer labels" all right on top of each other. I made the 4 visible objects all have explicit heights, and the spacers with no fixed heights, but set to be all the same:

    -(void)viewDidLoad {
        [super viewDidLoad];
    
        NSMutableDictionary *viewsDict = [NSMutableDictionary dictionary];
        for (int i=1; i<5; i++) { // Labels with titles
            UILabel *b = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 44)];
             b.text = @"This is my label";
            [b setTranslatesAutoresizingMaskIntoConstraints:NO];
            [viewsDict setObject:b forKey:[NSString stringWithFormat:@"b%d",i]];
        }
    
        for (int i=1; i<6; i++) { // Spacer labels
            UILabel *l = [[UILabel alloc ]init];
            [l setTranslatesAutoresizingMaskIntoConstraints:NO];
            [viewsDict setObject:l forKey:[NSString stringWithFormat:@"l%d",i]];
        }
    
        for (id obj in viewsDict.allKeys) 
            [self.view addSubview:viewsDict[obj]];
    
        NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[l1][b1][l2(==l1)][b2][l3(==l1)][b3][l4(==l1)][b4][l5(==l1)]|"
                                                                       options:NSLayoutFormatAlignAllLeading
                                                                       metrics:nil
                                                                         views:viewsDict];
    
    
        NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[b1]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDict];
    
    
        [self.view addConstraints:constraints];
        [self.view addConstraints:constraints2];
    } 
    

    To make the spaces different, I think you have to use the longer form of expressing constraints, rather than the visual format. The below code seems to work for me. I'm using the same definition of the views as above, except that I cut the number of titled labels to 3 and spacers to 4 to match you question. The relative spacing should be as in your example, 2:3:4:4.

    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:viewsDict[@"l1"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l1"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"b1"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b1"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"l2"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l2"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"b2"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con5 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b2"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"l3"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con6 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l3"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"b3"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con7 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b3"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:viewsDict[@"l4"] attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        NSLayoutConstraint *con8 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l4"] attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
        NSLayoutConstraint *con9 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l1"] attribute:NSLayoutAttributeHeight relatedBy:0 toItem:viewsDict[@"l2"] attribute:NSLayoutAttributeHeight multiplier:.66 constant:0];
        NSLayoutConstraint *con10 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l1"] attribute:NSLayoutAttributeHeight relatedBy:0 toItem:viewsDict[@"l3"] attribute:NSLayoutAttributeHeight multiplier:.5 constant:0];
        NSLayoutConstraint *con11 = [NSLayoutConstraint constraintWithItem:viewsDict[@"l1"] attribute:NSLayoutAttributeHeight relatedBy:0 toItem:viewsDict[@"l4"] attribute:NSLayoutAttributeHeight multiplier:.5 constant:0];
        NSLayoutConstraint *con12 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b1"] attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:100];
        NSLayoutConstraint *con13 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b2"] attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:100];
        NSLayoutConstraint *con14 = [NSLayoutConstraint constraintWithItem:viewsDict[@"b3"] attribute:NSLayoutAttributeLeading relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:100];
    
        NSArray *constraints = @[con1,con2,con3,con4,con5,con6,con7,con8,con9,con10,con11,con12,con13,con14];
        [self.view addConstraints:constraints];