使用自动布局约束时如何获取视图的当前宽度和高度?

问题描述 投票:0回答:5

我不是在谈论frame属性,因为从中你只能得到xib中视图的大小。我说的是当视图由于其约束而调整大小时(可能在旋转之后,或响应事件)。有没有办法获取它当前的宽度和高度?

我尝试迭代其约束来寻找宽度和高度约束,但这不是很干净,并且在存在内在约束时会失败(因为我无法区分两者)。此外,只有当它们实际上有宽度和高度约束时才有效,如果它们依赖其他约束来调整大小,则不会。

ios autolayout
5个回答
257
投票

答案是

[view layoutIfNeeded]

原因如下:

您仍然可以通过检查

view.bounds.size.width
view.bounds.size.height
(或框架,除非您使用
view.transform
,否则是等效的)来获取视图的当前宽度和高度。

如果您想要的是现有约束隐含的宽度和高度,那么答案不是手动检查约束,因为这需要您重新实现自动布局系统的整个约束求解逻辑才能解释那些限制。相反,您应该做的只是要求自动布局更新该布局,以便它解决约束并使用正确的解决方案更新 view.bounds 的值,然后检查 view.bounds。

如何要求自动布局更新布局?如果您希望自动布局在运行循环的下一回合更新布局,请调用

[view setNeedsLayout]

但是,如果您希望它立即更新布局,以便稍后可以在当前函数中立即访问新的边界值,或者在运行循环开始之前的另一点,那么您需要调用

[view setNeedsLayout]
[view layoutIfNeeded]

您问了第二个问题:“如果我没有直接引用它,如何更改高度/宽度约束?”。

如果您在 IB 中创建约束,最好的解决方案是在视图控制器或视图中创建 IBOutlet,以便您可以直接引用它。如果您在代码中创建了约束,那么您应该在创建它时保留内部弱属性中的引用。如果其他人创建了约束,那么您需要通过检查视图上的 view.constraints 属性(可能还有整个视图层次结构)并实现找到关键 NSLayoutConstraint 的逻辑来找到它。这可能是错误的方法,因为它还有效地要求您确定哪个特定约束决定了边界大小,而不能保证该问题有一个简单的答案。最终的边界值可能是具有多个约束、多个优先级等的非常复杂的系统的解决方案,因此没有任何单个约束是最终值的“原因”。


8
投票

我遇到了类似的问题,我需要向

UITableView
添加顶部和底部边框,并根据
UIStoryboard
中的约束设置调整大小。我能够使用
- (void)viewDidLayoutSubviews
访问更新的约束。这很有用,因此您不需要子类化视图并重写其布局方法。

/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
    CALayer *topBorder           = [CALayer layer];
    topBorder.frame              = CGRectMake(0.0f, self.tableView.frame.origin.y, 320.0f, 0.5f);
    topBorder.backgroundColor    = [UIColor redColor].CGColor;

    CALayer *bottomBorder        = [CALayer layer];
    bottomBorder.frame           = CGRectMake(0.0f, (self.tableView.frame.origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
    bottomBorder.backgroundColor = [UIColor redColor].CGColor;

    [self.view.layer addSublayer:topBorder];
    [self.view.layer addSublayer:bottomBorder];
}

/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
    [self addBorders];
}

如果不从

viewDidLayoutSubview
方法调用该方法,则仅正确绘制顶部边框,因为底部边框位于屏幕外的某个位置。


5
投票

对于那些可能仍然面临此类问题的人,尤其是使用 TableviewCell 时。

只需重写该方法:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

如果是 UITableViewCell 或 UICollectionViewCell,请创建单元格的子类并重写相同的方法:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

3
投票

使用

-(void)viewWillAppear:(BOOL)animated
并致电
[self.view layoutIfNeeded];
- 我已经尝试过了。

因为如果你使用

-(void)viewDidLayoutSubviews
它肯定会工作,但每次你的 UI 需要更新/更改时都会调用此方法。这将变得难以管理。软键是您使用布尔变量来避免这种调用循环。更好地使用
viewWillAppear
。请记住,如果再次加载视图(无需重新分配),也会调用
viewWillAppear


2
投票

框架仍然有效。最后,视图使用其框架属性来布局自身。它根据所有约束计算该框架。这些约束仅用于初始布局(以及在视图上调用layoutSubviews 的任何时间,例如旋转后)。之后,位置信息位于框架属性中。或者你有其他看法吗?

© www.soinside.com 2019 - 2024. All rights reserved.