以 Autolayout 视觉形式调整子视图的大小

Posted

技术标签:

【中文标题】以 Autolayout 视觉形式调整子视图的大小【英文标题】:Resize subviews in Autolayout visual form 【发布时间】:2013-10-08 07:00:18 【问题描述】:

我未能将我的应用从 Autoresize 迁移到 Autolayout 机制。我所需要的只是一个具有动态大小和子视图的视图,它们将连接到与它们的父视图相同大小的左上角。在 IB 中,我将 PieView(我的超级视图)的大小设置为 186x186。并让 IB 生成所有需要的约束(我将在代码中创建新的约束):

PieView.m -updateConstraints()

- (void)updateConstraints 
[super updateConstraints];
[self removeConstraintsAffectingViewAndSubviews];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];

CGFloat sizeCoef = 0.7f;
CGFloat percent = [self.category getFillinPercent] / 100.0f;
percent = percent > 1.0f ? 1.0f : percent;
sizeCoef += (1.0f - sizeCoef) * percent;

NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:self
                                                         attribute:NSLayoutAttributeWidth
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:1.0f
                                                          constant:100.f];//kDiameter * sizeCoef];

NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:self
                                                          attribute:NSLayoutAttributeHeight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:nil
                                                          attribute:NSLayoutAttributeNotAnAttribute
                                                         multiplier:1.0f
                                                           constant:100.0f];//kDiameter * sizeCoef];
//_imgEmptyCircle, _imgFullCircle - UIImageViews
NSDictionary *views = NSDictionaryOfVariableBindings(_imgEmptyCircle, _imgFullCircle, self);
NSDictionary *metrics = @@"height":@100.0;

[self addConstraints:@[width, height]];

NSString *visualForm = @"H:|[_imgEmptyCircle(height)][_imgFullCircle(height)]|";
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:visualForm
                                                                     options:0
                                                                     metrics:metrics
                                                                       views:views];
visualForm = @"V:|[_imgEmptyCircle(height)][_imgFullCircle(height)]|";
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:visualForm
                                                                      options:0
                                                                      metrics:metrics
                                                                        views:views];
[self addConstraints:verticalConstraints];
[self addConstraints:horizontalConstraints];

结果真让我吃惊。蓝色的如我所愿正确显示,但绿色的有奇怪的行为。

当然我有错误:无法同时满足约束。First imageView: NSIBPrototypingLayoutConstraint:0xa2795d0 'IB 在构建时为固定框架视图自动生成' V:[UIImageView:0x8a37150(186)]> NSLayoutConstraint:0xa0305c0 V:[UIImageView:0x8a37150(100)]第二个 imageView:同一个可能是 PieView: ( NSLayoutConstraint:0x8a40750 V:[CEPieView:0x8a36e50(100)], NSLayoutConstraint:0xa030570 V:|-(0)-[UIImageView:0x8a37150](名称:'|':CEPieView:0x8a36e50), NSLayoutConstraint:0xa0305c0 V:[UIImageView:0x8a37150(100)], NSLayoutConstraint:0xa0305f0 V:[UIImageView:0x8a37150]-(0)-[UIImageView:0xa277cf0]> NSLayoutConstraint:0xa030620 V:[UIImageView:0xa277cf0(100)], NSLayoutConstraint:0xa030650 V:[UIImageView:0xa277cf0]-(0)-| (名称:'|':CEPieView:0x8a36e50) )

请给我建议如何解决它。如何借助 AutoLayout 机制创建和旧的自动调整掩码(UIViewAutoresizingFlexibleHeight、UIViewAutoresizingFlexibleWidth)。任何帮助将不胜感激。

【问题讨论】:

你能解释一下哪个是绿色视图,哪个是蓝色视图?您的视图层次结构如何设置? PieView 有 3 个子视图。其中一个,最后一个,现在没有使用,在讨论中是多余的。第一个 imageView 有蓝色背景,第二个(在 IB 的中间)有绿色背景。谢谢回复 【参考方案1】:

您设置约束的方式是错误的。基本上,您要求超级视图为 100pts x 100pts,并包含两个子视图,每个子视图均为 100pts x 100pts,并且彼此相邻且位于彼此之上。因此,首先您的超级视图必须是 200pts 宽和/或高,然后您不能有两个彼此相邻且位于顶部的视图。 你真正想做的(我认为)是:

NSString *visualForm = @"H:|[_imgFullCircle]|"; // No need to explicitly set the height

然后添加相应的约束,然后:

visualForm = @"H:|[_imgEmptyCircle(height)]|";

并为此添加另一个约束,并为垂直约束做同样的事情。

基本上你会得到:

//_imgEmptyCircle, _imgFullCircle - UIImageViews
NSDictionary *views = NSDictionaryOfVariableBindings(_imgEmptyCircle, _imgFullCircle, self);

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imgEmptyCircle]|"
                                                                 options:0
                                                                 metrics:nil
                                                                   views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_imgFullCircle]|"
                                                                 options:0
                                                                 metrics:nil
                                                                   views:views]];                                                                       
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imgEmptyCircle]|"
                                                                 options:0
                                                                 metrics:nil
                                                                   views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imgFullCircle]|"
                                                                 options:0
                                                                 metrics:nil
                                                                   views:views]];    

【讨论】:

谢谢,我知道我的视觉格式出了什么问题。但我想动态调整超级视图的大小。在您的约束不起作用后,从我上面的代码中调用 [self addConstraints:@[width, height]];。因此,在我的情况下,我想将超级视图的大小从 IB 中的 186x186 调整为代码中的 100x100 并自动调整子视图的大小(也是 100x100)。谢谢! 怎么不工作了?它给你什么结果?通常这应该可以工作,因为子视图被限制为与父视图具有相同的大小(您也可以直接在 IB 中确定) 因此,superview 保持与 IB 中相同的大小。我的代码:....[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imgFullCircle]|" options:0 metrics:nil views:views]]; [self addConstraints:@[width, height]]; 截图 s16.postimg.org/rk14u68ut/… 你有什么错误吗?你能显示[自我约束]的输出吗?您是否尝试过查看您的 -updateContraints 方法何时被调用? 当我添加 `[self addConstraints:@[width, height]];` 时出现无法同时满足约束,我尝试在其中设置超级视图的大小。没有这条线就没有错误。这里有一些日志 (s2.postimg.org/4mzl1f72x/…)

以上是关于以 Autolayout 视觉形式调整子视图的大小的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIScrollView 和 AutoLayout 以编程方式创建控制器无法正确调整视图大小

调整子视图大小的自动布局问题

如何使用 Cocoa Autolayout 根据优先级调整两个子视图的大小?

Cocoa 自动布局和调整子视图的大小

AutoLayout动态调整UILabel高度和宽度

根据子视图调整超级视图的大小