我正在进入iOS编程并且使用固定数量的项目或多或少地掌握了自动布局。比如,我们有一个UILabel用于标题,UILabel用于副标题,然后约束的可视格式为'V:|-[title]-10-[subtitle]-|'
但是,如果我根据某些API响应动态创建子视图,该怎么办?例如,我需要添加40个子视图。我用视觉格式指定每个子视图并跟踪它们是不现实的。什么是正确的方法?
我想在我添加的每个子视图之后,然后我使用constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
基于上一个视图设置约束。这是要走的路,还是有更好的方法?
答案 0 :(得分:1)
我用视觉格式指定每个子视图并跟踪它们是不现实的
为什么不呢?你似乎认为这是某种“两种情况”。没有什么能阻止您使用可视化格式来构建约束集合。没有法律规定您必须将所有约束条件放入一个可视格式。
布局引擎不知道或关心您用于形成约束的符号。约束是约束!
考虑这段代码,我为滚动视图构建约束,并在其中包含30个标签:
var con = [NSLayoutConstraint]()
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[sv]|",
options:[], metrics:nil,
views:["sv":sv]))
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[sv]|",
options:[], metrics:nil,
views:["sv":sv]))
var previousLab : UILabel? = nil
for i in 0 ..< 30 {
let lab = UILabel()
// lab.backgroundColor = UIColor.redColor()
lab.translatesAutoresizingMaskIntoConstraints = false
lab.text = "This is label \(i+1)"
sv.addSubview(lab)
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|-(10)-[lab]",
options:[], metrics:nil,
views:["lab":lab]))
if previousLab == nil { // first one, pin to top
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:|-(10)-[lab]",
options:[], metrics:nil,
views:["lab":lab]))
} else { // all others, pin to previous
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:[prev]-(10)-[lab]",
options:[], metrics:nil,
views:["lab":lab, "prev":previousLab!]))
}
previousLab = lab
}
con.appendContentsOf(
NSLayoutConstraint.constraintsWithVisualFormat(
"V:[lab]-(10)-|",
options:[], metrics:nil,
views:["lab":previousLab!]))
NSLayoutConstraint.activateConstraints(con)
我正在使用视觉格式,但我在添加视图时正在做一个约束(这正是你所询问的)。
答案 1 :(得分:0)
答案实际上取决于您想要的布局,因为有更高级别的工具可用于制作布局。
从iOS 9开始,您可以使用UIStackView
来管理一行或一列视图。 By nesting stack views, you can easily make a grid of views.要了解UIStackView
,请先查看“Mysteries of Auto Layout, Part 1” from WWDC 2015。如果您在代码中执行所有布局,则可以使用TZStackView
,重新实现适用于iOS 7及更高版本的UIStackView
。
UICollectionView
是在网格或许多其他安排中布置视图的另一种工具。它比UIStackView
更复杂,但有很多介绍性材料可以教您如何使用它,例如“Introducing Collection Views” from WWDC 2012。
答案 2 :(得分:0)
我构建了一个动态布局引擎(水平布局和垂直布局)。
它接受一系列视图。
它将视图作为子视图添加到容器中。
这是垂直布局的通用布局引擎。享受。
@implementation UIView (VerticalLayout)
- (void)addControls:(NSArray*)controls
align:(VerticalAlignment)alignment
withHeight:(CGFloat)height
verticalPadding:(CGFloat)verticalPadding
horizontalPadding:(CGFloat)horizontalPadding
topPadding:(CGFloat)topPadding
bottomPadding:(CGFloat)bottomPadding
withWidth:(CGFloat)width
{
NSMutableDictionary* bindings = [[NSMutableDictionary alloc] init];
NSDictionary *metrics = @{
@"topPadding": @(topPadding),
@"bottomPadding": @(bottomPadding),
@"verticalPadding": @(verticalPadding),
@"horizontalPadding":@(horizontalPadding) };
NSMutableString* verticalConstraint = [[NSMutableString alloc] initWithString:@"V:"];
if (alignment == VerticalAlignTop || alignment == VerticalAlignStretchToFullHeight) {
[verticalConstraint appendString:@"|"];
}
for (UIView* view in controls) {
BOOL isFirstView = [controls firstObject] == view;
BOOL isLastView = [controls lastObject] == view;
[self addSubview: view];
// Add to vertical constraint string
NSString* viewName = [NSString stringWithFormat:@"v%p",view];
[bindings setObject:view forKey:viewName];
NSString* yLeadingPaddingString = @"";
NSString* yTrailingPadding = @"";
if (isFirstView && topPadding > 0) {
yLeadingPaddingString = @"-topPadding-";
}
else if (!isFirstView && verticalPadding > 0) {
yLeadingPaddingString = @"-verticalPadding-";
}
if (isLastView && bottomPadding > 0) {
yTrailingPadding = @"-bottomPadding-";
}
[verticalConstraint appendFormat:@"%@[%@%@]%@",
yLeadingPaddingString,
viewName,
height > 0 ? [NSString stringWithFormat:@"(%f)", height] : @"",
yTrailingPadding];
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:
[NSString stringWithFormat: @"H:|-horizontalPadding-[%@%@]%@|",
viewName,
(width > 0 ? [NSString stringWithFormat:@"(%lf)", width] : @""),
width > 0 ? @"-" : @"-horizontalPadding-"]
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:metrics
views:bindings];
// high priority, but not required.
for (NSLayoutConstraint* constraint in constraints) {
constraint.priority = 900;
}
// Add the horizontal constraint
[self addConstraints: constraints];
}
if (alignment == VerticalAlignBottom || alignment == VerticalAlignStretchToFullHeight) {
[verticalConstraint appendString:@"|"];
}
NSArray* constraints = [NSLayoutConstraint
constraintsWithVisualFormat:verticalConstraint
options:NSLayoutFormatAlignAllLeading
metrics:metrics
views:bindings];
for (NSLayoutConstraint* constraint in constraints) {
constraint.priority = 900;
}
// Add the vertical constraints for all these views.
[self addConstraints:constraints];
}