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

时间:2012-11-19 02:34:23

标签: ios autolayout

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

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

为什么这对我来说如此困难。 ARG!

5 个答案:

答案 0 :(得分:233)

答案是[view layoutIfNeeded]

原因如下:

通过检查view.bounds.size.widthview.bounds.size.height(或框架,除非您正在玩view.transform),您仍然可以获得视图的当前宽度和高度。

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

您如何要求自动布局更新布局?如果您希望自动布局在下一轮运行循环中更新布局,请调用[view setNeedsLayout]

但是,如果您希望它立即更新布局,那么您可以在当前函数中稍后立即访问新的边界值,或者在运行循环开始之前的另一个点,然后您需要致电[view setNeedsLayout][view layoutIfNeeded]

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

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

答案 1 :(得分: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方法调用方法,则只能正确绘制顶部边框,因为底部边框位于屏幕外的某处。

答案 2 :(得分:4)

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

只需覆盖方法:

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

如果是UITableViewCell或UICollectionViewCell,则创建单元格的子类并覆盖相同的方法:

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

答案 3 :(得分:3)

使用-(void)viewWillAppear:(BOOL)animated并致电[self.view layoutIfNeeded]; - 我尝试了它。

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

答案 4 :(得分:2)

框架仍然有效。最后,视图使用其frame属性来展示自己。它根据所有约束计算该帧。约束仅用于初始布局(并且任何时候在旋转之后的视图上调用layoutSubviews)。之后,位置信息在frame属性中。或者你看到了吗?