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

yuf*_*yuf 103 ios autolayout

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

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

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

alg*_*gal 238

答案是[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的逻辑来找到它.这可能是错误的方法,因为它还有效地要求您确定哪个特定约束确定了边界大小,当不能保证对该问题的简单答案时.最终边界值可以是一个非常复杂的多重约束系统的解决方案,

  • 一个*优秀*答案,也很好解释.一两个小时后把头发拉出来救了我. (16认同)
  • 为什么强制布局只是为了获得界限?这看起来效率低,而且界面复杂,这可能会很昂贵.而是从viewDidLayoutSubviews甚至viewWillLayoutSubviews访问最新的边界,让cocoa处理自己的布局时序.如果需要访问值或标志以设置属性,以避免多次调用(如果这是一个问题). (4认同)
  • `layoutIfNeeded`非常棒,并且可以使框架立即可用.但是,它还将强制在调用它的视图的子树中的所有视图上呈现约束.例如,如果要以编程方式添加视图,并在递归例程中对所有视图调用"layoutIfNeeded",则可能会发现视图层次结构渲染速度非常慢.(我很难学到这一点)正如优秀答案所提到的,'setNeedsLayout`效率更高,并且可以在下一个布局过程中使帧可用,理想情况下大约在1/60秒内发生. (2认同)

小智 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];
}
Run Code Online (Sandbox Code Playgroud)

如果不从viewDidLayoutSubview方法调用方法,则只能正确绘制顶部边框,因为底部边框位于屏幕外的某处.

  • viewDidLayoutSubviews被调用几次,你创建了大量的图层......你需要在添加*another*图层之前添加一些存在性检查. (3认同)

小智 5

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

只需覆盖该方法:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}
Run Code Online (Sandbox Code Playgroud)

在 UITableViewCell 或 UICollectionViewCell 的情况下,创建单元格的子类并覆盖相同的方法:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}
Run Code Online (Sandbox Code Playgroud)