我正在经历'自动布局比其价值更多的努力'阶段。 我变得越来越好,但有些部分不会点击&至少可以说是令人沮丧的。下面是图片,以帮助显示我在这里的位置,以及它从模拟器返回的内容:
中心'...'文字标签以V& H为中心。所有4个按钮都具有此标签的尾部底部空间约束。每个按钮彼此具有试验空间约束。
当我添加领先&尾随空间约束到UI编辑器的外边缘(上图)我得到的结果显示为我希望(下面)
然而旋转90度导致4个按钮压扁并且不可见(在某些尝试中,4个按钮刚刚相互重叠)。
我尝试了所有不同的约束组合,但我无法在两个方向上实现我希望的视图。这个问题可能会受到批评,但说实话,这是获得答案的唯一直接方式,甚至只是一些帮助。我发现在线教程&示例只是陈述我必须使用的工具,而不是冒险进入“略微超过基本”的UI元素定位
答案 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轴的位置,但也防止它们被纵向侧面压扁。