12

Possible Duplicate:
Autolayout Even Spacing

I'm trying to create a scrollable bar with buttons (similar to a UISegmentedControl). The superview is an UIScrollView. As soon as the buttons don't fit into the scrollview, the scrollview should be scrollable. So far, almost everything works fine:

With a lot of buttons (scrolled to the right):

Scrolled View

Not so many buttons:

View is not scrolling

Now, my goal is that if there is room for all buttons, they should be equally spread across the whole 320px view. How can I define constrains for the spaces in between the buttons?

Right now, I'm using the following constraints (self is a UIScrollView):

UIView *firstButton = self.buttons[0];

[self.buttonConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(5)-[firstButton]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(firstButton)]];

UIView *lastButton = [self.buttons lastObject];

[self.buttonConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"[lastButton]-(5)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(lastButton)]];

UIView *previousView = nil;

for (UIView *view in self.buttons) {
    if (previousView) {
        [self.buttonConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"[previousView]-(5)-[view]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(previousView, view)]];
    }
    previousView = view;
}

If I change the type of the superview from UIScrollView to an UIView, I get the following result, still not what I want, but at least it looks for the constraint of the last button that ties it to the right edge (makes sense, that this doesn't happen for the scrollview, as the content size is automatically set):

UIView as the superview

Any ideas?

Community
  • 1
  • 1
denbec
  • 1,321
  • 18
  • 25
  • When you say "equally spread across the whole 320px view", you mean the spaces between each button will all have the same width, correct? In your example code, you apply constraints spacing each view 5 points apart horizontally. Is 5 points a guess, or did you determine that your 4 buttons' widths plus 5 instances of 5 point spacings add up to equal the superview's width? – John Sauer Dec 16 '12 at 05:18

1 Answers1

20
- (void) viewWillLayoutSubviews {
    // UIButton *button1, *button2, *button3, *button 4 ;
    // NSMutableArray *constraintsForButtons ;

    float unusedHorizontalSpace = self.view.bounds.size.width - button1.intrinsicContentSize.width - button2.intrinsicContentSize.width - button3.intrinsicContentSize.width - button4.intrinsicContentSize.width ;
    NSNumber* spaceBetweenEachButton=  [NSNumber numberWithFloat: unusedHorizontalSpace / 5 ] ;

    [self.view removeConstraints:constraintsForButtons] ;
    [constraintsForButtons removeAllObjects] ;
    [constraintsForButtons addObjectsFromArray: [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-(space)-[button1]-(space)-[button2]-(space)-[button3]-(space)-[button4]-(space)-|"
                                                                                        options: NSLayoutFormatAlignAllCenterY
                                                                                        metrics: @{@"space":spaceBetweenEachButton}
                                                                                          views: NSDictionaryOfVariableBindings(button1,button2,button3,button4) ] ] ;
    [constraintsForButtons addObjectsFromArray: [NSLayoutConstraint constraintsWithVisualFormat: @"V:|[button1]"
                                                                                        options: 0
                                                                                        metrics: nil
                                                                                          views: NSDictionaryOfVariableBindings(button1) ] ] ;
    [self.view addConstraints:constraintsForButtons] ;
}

This isn't as pretty as yours, and it assumes there are 4 buttons, but it equally spaces them. That is, the empty spaces between the buttons all have the same width. This does not mean that the distance between the NSLayoutAttributeLeading of button1 and button2 is the same as the distance between button2 & button3's.

portrait landscape

John Sauer
  • 4,411
  • 1
  • 25
  • 33
  • 6
    Now _that's_ an answer. – jrturton Dec 16 '12 at 21:10
  • well, it doesn't completely rely on autolayout without your own calculations as i wished it could, but it's a working solution and is helping me in this case (also, as i didn't know that you can use the metrics parameter like that). thanks. – denbec Dec 17 '12 at 08:12
  • Yea, it'd be nicer to say " (button1's NSLayoutAttributeTrailing - button2's NSLayoutAttributeLeading) == (button2's NSLayoutAttributeTrailing - button3's NSLayoutAttributeLeading) ", etc., but I don't know of a way to. You _could_ initialize UIViews, leave them empty, and use them in a constraint like @"[emptyView1][button1][emptyView2(==emptyView1)][button2]…", but someone more knowledgeable might tell you that's a waste of resources. – John Sauer Dec 17 '12 at 12:26
  • 1
    The trick with this is if the spacing ends up weird like 23.333333. Then it breaks. The solution is to fmod it first to get any potential remainder, and then round down your spacing and add the remainder to the last one (shouldn't be noticeable). `CGFloat remainder = fmod(totalSpace, 3); CGFloat spacing = floor(totalSpace /3);` – Bob Spryn May 28 '13 at 01:31