自动布局:纵向到横向不一致

时间:2014-12-11 15:00:53

标签: ios autolayout

我正在经历'自动布局比其价值更多的努力'阶段。 我变得越来越好,但有些部分不会点击&至少可以说是令人沮丧的。下面是图片,以帮助显示我在这里的位置,以及它从模拟器返回的内容:

enter image description here

中心'...'文字标签以V& H为中心。所有4个按钮都具有此标签的尾部底部空间约束。每个按钮彼此具有试验空间约束。 enter image description here

当我添加领先&尾随空间约束到UI编辑器的外边缘(上图)我得到的结果显示为我希望(下面)

enter image description here

然而旋转90度导致4个按钮压扁并且不可见(在某些尝试中,4个按钮刚刚相互重叠)。

enter image description here

我尝试了所有不同的约束组合,但我无法在两个方向上实现我希望的视图。这个问题可能会受到批评,但说实话,这是获得答案的唯一直接方式,甚至只是一些帮助。我发现在线教程&示例只是陈述我必须使用的工具,而不是冒险进入“略微超过基本”的UI元素定位

2 个答案:

答案 0 :(得分:0)

这是我为NSLayoutConstraints写的自定义类别:

首先,NSLayoutConstraint+ConstructorAdditions.h文件:

//  NSLayoutConstraint+ConstructorAdditions.h
//
// The methods in this category can be used to create NSLayoutConstraints programmatically
// without taking the NSLayoutConstraints constructors.
// Note: view1 and view2 must be in the same subview hierarchy. If not, adding NSLayoutConstraints using these methods won't have no effect.
//
// Example for the right order of method calls creating Constraints:
//
// UIView* mySubview = [UIView alloc] init];
// [self.contentView addSubview: mySubview];
// [self.contentView addConstraint: [self height: 10.0 forView: mySubview]];


#import <UIKit/UIKit.h>

@interface NSLayoutConstraint (ConstructorAdditions)



// returns constraints that align view to top, leading, bottom and trailing edges of the superview according to the assigned padding value.
// the constraints in the returned array are (from index 0 to 3) in this order:
// leading, top, trailing, bottom
+ (NSArray*) makeView: (UIView*) view
fillBoundsOfSuperview: (UIView*) superview
      verticalPadding: (CGFloat) vPadding
    horizontalPadding: (CGFloat) hPadding;


// align edges of two views
// if one view is the superview, put it at the second position in the array
+ (NSLayoutConstraint*) alignEdge: (NSLayoutAttribute) edge
                          ofViews: (NSArray*) /*UIView*/ views
                         relation: (NSLayoutRelation) relation
                          spacing: (CGFloat) spacing;



// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing
                                ofViews: (NSArray*) /*UIView*/ views
                               flexible: (BOOL) flexible
                               inMaximum: (BOOL) inMax;


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
                                 flexible: (BOOL) flexible
                                 inMaximum: (BOOL) inMax;




// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing ofViews: (NSArray*) /*UIView*/ views;


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing betweenViews: (NSArray*) /*UIView*/ views;




// height constraints
+ (NSArray*) equalHeightOfViews: (NSArray*) views
                         toView: (UIView*) view
                       distance: (CGFloat) distance
                       relation: (NSLayoutRelation) relation
                     multiplier: (CGFloat) multiplier;
// fix heights
+ (NSLayoutConstraint*) height: (CGFloat) height forView: (UIView*) view;
+ (NSLayoutConstraint*) maxHeight: (CGFloat) height
                          forView: (UIView*) view;
+ (NSLayoutConstraint*) minHeight: (CGFloat) height
                          forView: (UIView*) view;

// width constraints
+ (NSArray*) equalWidthOfViews: (NSArray*) views
                        toView: (UIView*) view
                      distance: (CGFloat) distance
                      relation: (NSLayoutRelation) relation
                    multiplier: (CGFloat) multiplier;
// fix widths
+ (NSLayoutConstraint*) width: (CGFloat) width forView: (UIView*) view;
+ (NSLayoutConstraint*) maxWidth: (CGFloat) width
                         forView: (UIView*) view;
+ (NSLayoutConstraint*) minWidth: (CGFloat) width
                         forView: (UIView*) view;




// center vertically
+ (NSLayoutConstraint*) centerView: (UIView*) view
             verticallyInContainer: (UIView*) container;



// center horizontally
+ (NSLayoutConstraint*) centerView: (UIView*) view
            hoizontallyInContainer: (UIView*) container;



@end

这里是NSLayoutConstraint+ConstructorAdditions.m文件:

#import "NSLayoutConstraint+ConstructorAdditions.h"

@implementation NSLayoutConstraint (ConstructorAdditions)






+ (NSArray*) makeView: (UIView*) view fillBoundsOfSuperview: (UIView*) superview verticalPadding: (CGFloat) vPadding horizontalPadding: (CGFloat) hPadding
{
    /* padding must be > 0 !*/
    hPadding = hPadding < 0 ? 0 : hPadding;
    vPadding = vPadding < 0 ? 0 : vPadding;
    NSLayoutConstraint* top = [NSLayoutConstraint alignEdge: NSLayoutAttributeTop ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: vPadding];
    NSLayoutConstraint* leading = [NSLayoutConstraint alignEdge: NSLayoutAttributeLeading ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: hPadding];
    NSLayoutConstraint* trailing = [NSLayoutConstraint alignEdge: NSLayoutAttributeTrailing ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: hPadding];
    NSLayoutConstraint* bottom = [NSLayoutConstraint alignEdge: NSLayoutAttributeBottom ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: vPadding];
    //NSLayoutConstraint* width = [NSLayoutConstraint equalWidthOfViews: @[view, superview] distance: -2*hPadding relation: NSLayoutRelationEqual multiplier: 1.0][0];
    //NSLayoutConstraint* height = [NSLayoutConstraint equalHeightOfViews: @[view, superview] distance: -2*vPadding relation: NSLayoutRelationEqual multiplier: 1.0][0];
    return @[leading, top, trailing, bottom];
}







// align edges of two views
// if one view is the superview, put it at the second position in the array
+ (NSLayoutConstraint*) alignEdge: (NSLayoutAttribute) edge
                          ofViews: (NSArray*) /*UIView*/ views
                         relation: (NSLayoutRelation) relation
                          spacing: (CGFloat) spacing {
    NSLayoutConstraint* constraint = nil;
    if (views.count == 2) {
        if (edge == NSLayoutAttributeBaseline || edge == NSLayoutAttributeTrailing || edge == NSLayoutAttributeBottom || edge == NSLayoutAttributeRight) {
            spacing = -spacing;
        }
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: edge
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: edge
                                                 multiplier: 1.0
                                                   constant: spacing];
    }
    return constraint;
}


// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing
                                ofViews: (NSArray*) /*UIView*/ views
                               flexible: (BOOL) flexible
                               inMaximum: (BOOL) inMax {
    NSLayoutConstraint* constraint = nil;

    NSLayoutRelation relation = flexible ? (inMax ? NSLayoutRelationGreaterThanOrEqual : NSLayoutRelationLessThanOrEqual) : NSLayoutRelationEqual;

    if (views.count == 2) {
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: NSLayoutAttributeBottom
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: NSLayoutAttributeTop
                                                 multiplier: 1.0
                                                   constant: -spacing];
    }
    return constraint;
}


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
                                 flexible: (BOOL) flexible
                                 inMaximum: (BOOL) inMax {
    NSLayoutConstraint* constraint = nil;
    NSLayoutRelation relation = flexible ? (inMax ? NSLayoutRelationGreaterThanOrEqual : NSLayoutRelationLessThanOrEqual) : NSLayoutRelationEqual;
    if (views.count == 2) {
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: NSLayoutAttributeTrailing
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: NSLayoutAttributeLeading
                                                 multiplier: 1.0
                                                   constant: -spacing];
    }
    return constraint;
}






// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing ofViews: (NSArray*) /*UIView*/ views
{
    NSLayoutConstraint* verticalSpacing = nil;
    if (views.count == 2) {
        verticalSpacing = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0] attribute: NSLayoutAttributeBottom relatedBy: NSLayoutRelationEqual toItem: [views objectAtIndex: 1] attribute: NSLayoutAttributeTop multiplier: 1.0 constant: -spacing];
    }
    return verticalSpacing;
}



// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
{
    NSLayoutConstraint* horizontalSpacing = nil;
    if (views.count == 2) {
        horizontalSpacing = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0] attribute: NSLayoutAttributeTrailing relatedBy: NSLayoutRelationEqual toItem: [views objectAtIndex: 1] attribute: NSLayoutAttributeLeading multiplier: 1.0 constant: -spacing];
    }
    return horizontalSpacing;
}








+ (NSArray*) equalHeightOfViews: (NSArray*) views
                         toView: (UIView*) view
                       distance: (CGFloat) distance
                       relation: (NSLayoutRelation) relation
                     multiplier: (CGFloat) multiplier {
    NSMutableArray* constraints = [[NSMutableArray alloc] initWithCapacity: views.count];

    for (UIView* aView in views) {
        [constraints addObject: [NSLayoutConstraint  constraintWithItem: aView
                                                              attribute: NSLayoutAttributeHeight
                                                              relatedBy: relation
                                                                 toItem: view
                                                              attribute: NSLayoutAttributeHeight
                                                             multiplier: multiplier
                                                               constant: distance]];
    }
    return constraints;
}



+ (NSLayoutConstraint*) height: (CGFloat) height forView: (UIView*) view {
    NSLayoutConstraint* constraint = nil;
    constraint = [NSLayoutConstraint constraintWithItem: view
                                              attribute: NSLayoutAttributeHeight
                                              relatedBy: NSLayoutRelationEqual
                                                 toItem: nil
                                              attribute: NSLayoutAttributeNotAnAttribute
                                             multiplier: 1.0
                                               constant: height];
    return constraint;
}


+ (NSLayoutConstraint*) maxHeight: (CGFloat) height
                          forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeHeight
                                                                  relatedBy: NSLayoutRelationLessThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: height];
    return constraint;

}


+ (NSLayoutConstraint*) minHeight: (CGFloat) height
                          forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeHeight
                                                                  relatedBy: NSLayoutRelationGreaterThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: height];
    return constraint;
}



+ (NSArray*) equalWidthOfViews: (NSArray*) views
                        toView: (UIView*) view
                      distance: (CGFloat) distance
                      relation: (NSLayoutRelation) relation
                    multiplier: (CGFloat) multiplier {
    NSMutableArray* constraints = [[NSMutableArray alloc] initWithCapacity: views.count];

    for (UIView* aView in views) {
        [constraints addObject: [NSLayoutConstraint  constraintWithItem: aView
                                                              attribute: NSLayoutAttributeWidth
                                                              relatedBy: relation
                                                                 toItem: view
                                                              attribute: NSLayoutAttributeWidth
                                                             multiplier: multiplier
                                                               constant: distance]];
    }
    return constraints;
}



+ (NSLayoutConstraint*) width: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}


+ (NSLayoutConstraint*) maxWidth: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationLessThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}


+ (NSLayoutConstraint*) minWidth: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationGreaterThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}



// center vertically
+ (NSLayoutConstraint*) centerView: (UIView*) view verticallyInContainer: (UIView*) container {
    NSLayoutConstraint* centerY = [NSLayoutConstraint constraintWithItem: view
                                                               attribute: NSLayoutAttributeCenterY
                                                               relatedBy: NSLayoutRelationEqual
                                                                  toItem: container
                                                               attribute: NSLayoutAttributeCenterY
                                                              multiplier: 1.0
                                                                constant: 0];
    return centerY;
}



// center horizontally
+ (NSLayoutConstraint*) centerView: (UIView*) view hoizontallyInContainer: (UIView*) container {
    NSLayoutConstraint* centerX = [NSLayoutConstraint constraintWithItem: view
                                                               attribute: NSLayoutAttributeCenterX
                                                               relatedBy: NSLayoutRelationEqual
                                                                  toItem: container
                                                               attribute: NSLayoutAttributeCenterX
                                                              multiplier: 1.0
                                                                constant: 0];


    return centerX;
}





@end

答案 1 :(得分:0)

在您的初始图片中,标签看起来像橙色的原因是因为您的约束中存在歧义:特别是它们没有任何东西告诉它们应该相对于x轴坐在哪里。它们垂直地连接到中心,但是水平地它们仅相互连接,并且因为它们都不作为x轴锚附着到边缘或其他任何东西上,所以存在歧义。

在第二张图片中,您已通过将链的两侧固定到视图边缘来解决此问题。然而,在肖像中,这会让他们感到困惑,因为那些外部锚点试图保持原位,而是选择在标签上挤压宽度约束。

以下是解决此问题的方法:选择一个标签(不一定是全部)并为容器的水平中心赋予约束,在本例中为超级视图。

这将告知标签它们相对于x轴的位置,但也防止它们被纵向侧面压扁。

horizontal center