将问题简化为X轴以简化。
给定具有共同祖先的2个或更多视图的数组,我们如何使用autolayout均匀分布其X中心,以便:
数组按顺序包含视图。对于这些观点及其共同祖先,没有其他任何东西可以被假定。特别是:
在代码中(使用UIView
,但同样适用于NSView
):
- (NSArray*)constraintsByDistributingCenterXOfViews:(NSArray*)views
{
const NSInteger count = views.count;
NSAssert(count >= 2, @"Array must contain at least 2 views");
NSMutableArray *constraints = [NSMutableArray array];
UIView *sharedAncestor = [views sharedAncestor]; // Util method
UIView *firstView = [views firstObject];
[constraints addObject:[firstView constraintByAligningLeftToView:sharedAncestor]]; // Util method
UIView *previousView = [self firstObject];
for (NSInteger i = 1; i < count - 1; i++)
{
UIView *currentView = views[i];
NSLayoutConstraint *constraint = ? // What would go here?
[constraints addObject:constraint];
previousView = currentView;
}
UIView *lastView = [views lastObject];
[constraints addObject:[lastView constraintByAligningRightToView:sharedAncestor]]; // Util method
return constraints;
}
答案 0 :(得分:1)
我认为这应该有效。它创建了间隔物,并在两侧的视图中心和间隔物的左右边缘之间增加了约束。假设您已创建了所有视图,但尚未将其添加到超级视图中,则会设置该方法。像这样称呼它,
[self equallySpaceCentersOfViews:@[l1,l2,l3,l4] inView:someView];
// add a constraint here to vertically place one of the views in someView (all the views have their centerY's equal)
这是方法,
-(void)equallySpaceCentersOfViews:(NSArray *) views inView:(UIView *) superview {
//create and add all the spacers to the superview
NSMutableArray *spacers = [NSMutableArray new];
for (int i =0; i<views.count - 1; i++) {
UIView *spacer = [UIView new];
spacer.translatesAutoresizingMaskIntoConstraints = NO;
[superview addSubview:spacer];
[spacers addObject:spacer];
}
//Add all the views to the superview.
for (UIView *obj in views) {
[obj setTranslatesAutoresizingMaskIntoConstraints:NO];
[superview addSubview:obj];
}
// Create the constraints to the two edges
[superview addConstraint:[NSLayoutConstraint constraintWithItem:views[0] attribute:NSLayoutAttributeLeft relatedBy:0 toItem:superview attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:views.lastObject attribute:NSLayoutAttributeRight relatedBy:0 toItem:superview attribute:NSLayoutAttributeRight multiplier:1 constant:0]];
//Create the constraints between the views and spacers
[views enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
[superview addConstraint:[NSLayoutConstraint constraintWithItem:obj attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:spacers[idx] attribute:NSLayoutAttributeLeft multiplier:1 constant:0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:obj attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:spacers[idx] attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:views[idx+1] attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:spacers[idx] attribute:NSLayoutAttributeRight multiplier:1 constant:0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:views[idx+1] attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:spacers[idx] attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
if (idx+1 == views.count-1) *stop = YES;
}];
//Make all the spacers have the same width
[spacers enumerateObjectsUsingBlock:^(UIView *spacer, NSUInteger idx, BOOL *stop) {
[superview addConstraint:[NSLayoutConstraint constraintWithItem:spacer attribute:NSLayoutAttributeWidth relatedBy:0 toItem:spacers[idx+1] attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
if (idx+1 == spacers.count-1) *stop = YES;
}];
}
这给出了以下四个不同宽度标签的结果,
答案 1 :(得分:0)
我能想到实现这一目标的最佳方法是使用方法......
constraintWithItem: attribute: relatedBy: toItem: attribute: multiplier: constant:
要在超视图中均匀地分隔子视图中心,将子视图的NSLayoutAttributeCenterX
约束到NSLayoutAttributeCenterX
超级视图,并使用乘数变量来区分它们......
CGFloat multiplier = (2.0 / (count - 1)) * position
其中count
为array.count
,position
为array
内的观看索引。这会使视图均匀分隔,但第一个和最后一个视图不会按要求对齐...
为了正确对齐第一个视图,我们只需将constant
设置为frame.size.wdith / 2
。
为了正确对齐上一个视图,我们只需将constant
设置为-(frame.size.width / 2)
...
越来越近,但间距有点不合适,所以我们需要再次使用constant
和偏移。首先,我们需要第一个和最后一个视图的总宽度......
UIView *viewFirst = array[0];
CGFloat widthFirst = viewFirst.frame.size.width;
UIView *viewLast = array[array.count - 1];
CGFloat widthLast = viewLast.frame.size.width;
CGFloat offset = widthFirst + widthLast;
现在我们可以使用此功能,结合count
和position
来抵消所有其他视图......
CGFloat middle = (count - 1) / 2; // work out the centre of the array
CGFloat constant = ((offset / 2) / (count - 1)) * -(position - middle);
将这一切放在一个方法中......
- (void)addConstraintsToView:(UIView *)view position:(NSInteger)position count:(NSInteger)count offset:(CGFloat)offset {
view.translatesAutoresizingMaskIntoConstraints = NO;
[view addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:view.frame.size.width]];
[view addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:view.frame.size.height]];
CGFloat multiplier = (2.0 / (count - 1)) * position;
CGFloat middle = (count - 1) / 2;
CGFloat standard = ((offset / 2) / (count - 1)) * -(position - middle);
CGFloat constant = (position == 0) ? view.frame.size.width / 2 : (position == count - 1) ? -view.frame.size.width / 2 : standard;
[self.mainView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.mainView
attribute:NSLayoutAttributeCenterX
multiplier:multipler
constant:constant]];
[self.mainView addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.mainView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
}
所以在viewDidLoad
中,计算偏移并迭代遍历每次调用此方法的views数组......
UIView *viewFirst = array[0];
CGFloat widthFirst = viewFirst.frame.size.width;
UIView *viewLast = array[array.count - 1];
CGFloat widthLast = viewLast.frame.size.width;
CGFloat offset = widthFirst + widthLast;
for(NSInteger i = 0; i < array.count; i++) {
UIView *view = array[i];
[self.mainView addSubview:view];
[self addConstraintsToView:view position:i count:array.count offset:offset];
}
嘿presto ...
编辑: 只是注意到这不是很正确,因为当第一个和最后一个视图的宽度不同时,它不能正确地偏移,但希望你能得到这个想法(如果它们都是相同的话,它会完美地工作)