ios 使用自动布局约束时如何获取视图的当前宽度和高度?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13446920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I get a view's current width and height when using autolayout constraints?
提问by yuf
I'm not talking about the frame property, because from that you can only get the view's size in the xib. I'm talking about when the view is resized because of its constraints (maybe after a rotation, or in response to an event). Is there a way to get its current width and height?
我不是在谈论 frame 属性,因为从中你只能在 xib 中获得视图的大小。我说的是视图何时因约束而调整大小(可能在旋转之后,或响应事件)。有没有办法获得它当前的宽度和高度?
I tried iterating through its constraints looking for width and height constraints, but that's not very clean and fails when there are intrinsic constraints (since I can't differentiate between the two). Also, that only works if they actually have width and height constraints, which they don't if they rely on other constraints to resize.
我尝试遍历其约束以寻找宽度和高度约束,但这不是很干净,并且在存在内在约束时失败(因为我无法区分两者)。此外,这仅在它们实际上具有宽度和高度约束时才有效,如果它们依赖其他约束来调整大小,则它们不会。
Why is this so difficult for me. ARG!
为什么这对我来说如此困难。阿格!
回答by algal
The answer is [view layoutIfNeeded]
.
答案是[view layoutIfNeeded]
。
Here's why:
原因如下:
You still get the view's current width and height by inspecting view.bounds.size.width
and view.bounds.size.height
(or the frame, which is equivalent unless you're playing with the view.transform
).
您仍然可以通过检查view.bounds.size.width
和view.bounds.size.height
(或框架,除非您使用 ,否则等效)来获得视图的当前宽度和高度view.transform
。
If what you want is the width and height implied by your existing constraints, the answer is not to inspect the constraints manually, since that would require you to re-implement the entire constraint-solving logic of the auto layout system in order to interpret those constraints. Instead, what you should do is just ask auto layout to update that layout, so that it solves the constraints and updates the value of view.bounds with the correct solution, and then you inspect the view.bounds.
如果您想要的是现有约束隐含的宽度和高度,答案不是手动检查约束,因为这需要您重新实现自动布局系统的整个约束解决逻辑,以便解释这些约束。相反,您应该做的只是要求自动布局更新该布局,以便它解决约束并使用正确的解决方案更新 view.bounds 的值,然后您检查 view.bounds。
How do you ask auto layout to update the layout? Call [view setNeedsLayout]
if you want auto layout to update the layout on the next turn of the run loop.
你如何要求自动布局更新布局?[view setNeedsLayout]
如果您希望自动布局在运行循环的下一轮更新布局,请调用。
However, if you want it to update the layout immediately, so you can immediately access the new bounds valuelater within your current function, or at another point before the turn of the run loop, then you need to call [view setNeedsLayout]
and [view layoutIfNeeded]
.
但是,如果您希望它立即更新布局,以便您可以稍后在当前函数中立即访问新的边界值,或者在轮到运行循环之前的另一个点,那么您需要调用[view setNeedsLayout]
and [view layoutIfNeeded]
。
You asked a second question: "how can I change a height/width constraint if I don't have a reference to it directly?".
你问了第二个问题:“如果我没有直接引用它,我该如何更改高度/宽度约束?”。
If you create the constraint in IB, the best solution is to create an IBOutlet in your view controller or your view so you do have a direct reference to it. If you created the constraint in code, then you should hold onto a reference in an internal weak property at the time when you created it. If someone else created the constraint, then you need to find it by examining the examining the view.constraints property on the view, and possibly the entire view hierarchy, and implementing logic which finds the crucial NSLayoutConstraint. This is probably the wrong way to go, since it also effectively requires you to determine which particular constraint determined the bounds size, when there's not guaranteed to be a simple answer to that question. The final bounds value could be the solution to a very complicated system of multiple constraints, with multiple priorities, etc., so that no single constraint is the "cause" of the final value.
如果您在 IB 中创建约束,最好的解决方案是在您的视图控制器或视图中创建一个 IBOutlet,以便您可以直接引用它。如果您在代码中创建了约束,那么您应该在创建它时保留内部弱属性中的引用。如果其他人创建了约束,那么您需要通过检查视图上的 view.constraints 属性来找到它,可能还有整个视图层次结构,并实现找到关键 NSLayoutConstraint 的逻辑。这可能是错误的方法,因为它也有效地要求您确定哪个特定约束决定了边界大小,而不能保证对该问题有一个简单的答案。最终边界值可能是一个非常复杂的多重约束系统的解决方案,
回答by Brandon Read
I had a similar issue where I needed to add a top and bottom border to a UITableView
that resizes based on its constraints setup in the UIStoryboard
. I was able to access the updated constraints with - (void)viewDidLayoutSubviews
. This is useful so that you do not need to subclass a view and override its layout method.
我有一个类似的问题,我需要向 a 添加顶部和底部边框,该边框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];
}
Without calling the method from the viewDidLayoutSubview
method, only the top border is drawn correctly, as the bottom border is somewhere offscreen.
如果不从viewDidLayoutSubview
方法调用该方法,则只会正确绘制顶部边框,因为底部边框位于屏幕外的某处。
回答by Mayank Pahuja
For those who may still be facing such issues, especially with TableviewCell.
对于那些可能仍然面临此类问题的人,尤其是使用 TableviewCell 的人。
Just override the method:
只需覆盖该方法:
-(void)layoutSubviews
{
//your code here like drawing a shadow
}
In case of UITableViewCell or UICollectionViewCell create a subclass of the cell and override the same method:
在 UITableViewCell 或 UICollectionViewCell 的情况下,创建单元格的子类并覆盖相同的方法:
-(void)layoutSubviews
{
//your code here like drawing a shadow
}
回答by Mayank Pahuja
Use -(void)viewWillAppear:(BOOL)animated
and call [self.view layoutIfNeeded];
- It works I have tried.
使用-(void)viewWillAppear:(BOOL)animated
和调用 [self.view layoutIfNeeded];
- 我试过了。
because if you use -(void)viewDidLayoutSubviews
it will work definitely but this method is called every time your UI demands updations/changes. Which will get hard to manage. Soft key is you use a bool variable to avoid such loop of calls. better use viewWillAppear
. Remember viewWillAppear
will also be called if view is loaded back again (without reallocating).
因为如果您使用-(void)viewDidLayoutSubviews
它肯定会起作用,但是每次您的 UI 需要更新/更改时都会调用此方法。这将变得难以管理。软键是您使用 bool 变量来避免此类调用循环。更好地使用viewWillAppear
。viewWillAppear
如果再次加载视图(不重新分配),也会调用记住。
回答by borrrden
The frame is still valid. In the end, the view uses its frame property to lay itself out. It calculates that frame based on all the constraints. The constraints are only used for the initial layout (and any time layoutSubviews is called on a view like after a rotation). After that, the position info is in the frame property. Or are you seeing otherwise?
该框架仍然有效。最后,视图使用它的 frame 属性来布局自己。它根据所有约束计算该帧。约束仅用于初始布局(并且任何时候在视图上调用 layoutSubviews 就像在旋转之后一样)。之后,位置信息在 frame 属性中。或者你看到的不是?