1

I use following function to space a dynamic number of views across a View (with autolayout):

-(NSArray*)spaceViews:(NSArray *)views onAxis:(UILayoutConstraintAxis)axis
{
    NSAssert([views count] > 1,@"Can only distribute 2 or more views");

    NSLayoutAttribute attributeForView;
    NSLayoutAttribute attributeToPin;

    switch (axis) {
        case UILayoutConstraintAxisHorizontal:
            attributeForView = NSLayoutAttributeCenterX;
            attributeToPin = NSLayoutAttributeRight;
            break;
        case UILayoutConstraintAxisVertical:
            attributeForView = NSLayoutAttributeCenterY;
            attributeToPin = NSLayoutAttributeBottom;
            break;
        default:
            return @[];
    }

    CGFloat fractionPerView = 1.0 / (CGFloat)([views count] + 1);

    NSMutableArray *constraints = [NSMutableArray array];
    [views enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop)
    {
        CGFloat multiplier = fractionPerView * (idx + 1.0);
        [constraints addObject:[NSLayoutConstraint constraintWithItem:view 
                                                            attribute:attributeForView 
                                                            relatedBy:NSLayoutRelationEqual 
                                                               toItem:self 
                                                            attribute:attributeToPin 
                                                           multiplier:multiplier 
                                                             constant:0.0]];
    }];

    [self addConstraints:constraints];
    return [constraints copy];
}

(The function is from UIView-Autolayout)

The problem is that it has margins. How could this method be changed in order to evenly space the views without margins?

UPDATE

It seems that the method is not working correctly after all, the margins on the outer items are much higher than at the rest.

As an example I changed the code for the left arm to:

self.leftArm = [UIView autoLayoutView];
self.leftArm.backgroundColor = [UIColor grayColor];

[self.view addSubview:self.leftArm];

[self.leftArm pinAttribute:NSLayoutAttributeRight toAttribute:NSLayoutAttributeLeft ofItem:self.body withConstant:-10.0];
[self.leftArm pinAttribute:NSLayoutAttributeTop toSameAttributeOfItem:self.body withConstant:10.0];
[self.leftArm constrainToSize:CGSizeMake(20.0, 200.0)];

Now the robot looks like this:

enter image description here

Note that at the left arm the views are NOT evenly distributed, the margin on top and at the bottom are much higher. I can reproduce the same behavior horizontally and with less items.

I have successfully removed the margins by aligning the outer views with the sides of the superview and aligning the rest within the space between. But now, due to this problem, I always have bigger spaces between the outer views and the views next to them as between the rest.

Does anyone know how to correct this?

UPDATE 2

I have created a fork and added my function to it, I also extended the robot example so you can see what I mean.

Please take a look.

Daniel
  • 20,420
  • 10
  • 92
  • 149

2 Answers2

2

It looks as though this code is from UIView-Autolayout. The latest version of the library has a new method which lets you stop the spacing from being added to edges:

-(NSArray*)spaceViews:(NSArray*)views
               onAxis:(UILayoutConstraintAxis)axis
          withSpacing:(CGFloat)spacing
     alignmentOptions:(NSLayoutFormatOptions)options
    flexibleFirstItem:(BOOL)flexibleFirstItem
  applySpacingToEdges:(BOOL)spaceEdges;

Just call this method instead and pass NO to the last argument.

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
James Frost
  • 6,960
  • 1
  • 33
  • 42
  • Unfortunately this method has a parameter "spacing", where the distance between views is defined. (I already tried that) – Daniel Mar 11 '15 at 10:06
  • You could pass 0 for spacing? If you don't want spacing between the views, what is it that the original method you posted isn't doing as you'd like? – James Frost Mar 11 '15 at 10:10
  • I'm not sure what you want is possible, in that case. The spaceViews:onAxis method distributes the centers of the views evenly along the axis, letting them occupy their own intrinsic size. The methods with spacing calculate a width and forces them to occupy equal widths. If the views are different sizes, how can you make "even" spacing? – jrturton Mar 11 '15 at 10:12
  • 1
    The views that I am adding are UIImageViews, they get expanded with this function (with the one I posted they had margins). But now that I think of it, I could just include them centered in another view that could get expanded.. problem solved! – Daniel Mar 11 '15 at 10:12
  • my first idea was to align the first view left, the last right and distribute the rest evenly across the view-the space the 2 views occupy. But that's more difficult. And I am not sure if I can get the sizes of the first and last view without using frame – Daniel Mar 11 '15 at 10:14
  • Ehhmm, if I add them in another view and they get expanded... I get margins again – Daniel Mar 11 '15 at 10:22
  • @jrturton my first idea did work, but it has a bug, please see my update. – Daniel Mar 11 '15 at 15:27
0

I have extended jrturton's UIView-Autolayout (based on this answer) and created a pull request.

It is now possible to distribute the views evenly without margins by calling the new function:

-(NSArray*)spaceViews:(NSArray *)views 
               onAxis:(UILayoutConstraintAxis)axis
           withMargin:(BOOL)margin

and setting the margin parameter to NO.

You can already find that version of UIView-Autolayout here.

The brand new robot with evenly spaced views as teeth: Robot

Community
  • 1
  • 1
Daniel
  • 20,420
  • 10
  • 92
  • 149