Bri*_*kel 6 iphone uikit ios autolayout
我有一个可重复使用的视图,我将使用UITableViewCell's和UICollectionViewCell,并需要获取其尺寸tableView:heightForRowAtIndexPath:.一些子视图里面有东西,layoutSubviews所以我不能打电话systemLayoutForContentSize:,而我的计划是:
我遇到的问题是,我不能强制视图布局而不将其插入视图并等待runloop.
我提炼了一个相当无聊的例子.这是View.xib.子视图未对齐以突出显示视图永远不会布局到基线位置:

在主线程上我打电话:
UIView *view = [[UINib nibWithNibName:@"View" bundle:nil] instantiateWithOwner:nil options:nil][0];
NSLog(@"Subviews: %@", view.subviews);
view.frame = CGRectMake(0, 0, 200, 200);
[view updateConstraints];
[view layoutSubviews];
NSLog(@"Subviews: %@", view.subviews);
[self.view addSubview:view];
[view updateConstraints];
[view layoutSubviews];
NSLog(@"Subviews: %@", view.subviews);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Subviews: %@", view.subviews);
});
Run Code Online (Sandbox Code Playgroud)
我得到以下视图信息:
1) "<UIView: 0x8bad9e0; frame = (50 50; 220 468); autoresize = W+H; layer = <CALayer: 0x8be0070>>"
2) "<UIView: 0x8bad9e0; frame = (50 50; 220 468); autoresize = W+H; layer = <CALayer: 0x8be0070>>"
3) "<UIView: 0x8bad9e0; frame = (50 50; 220 468); autoresize = W+H; layer = <CALayer: 0x8be0070>>"
4) "<UIView: 0x8bad9e0; frame = (0 100; 100 100); autoresize = W+H; layer = <CALayer: 0x8be0070>>"
Run Code Online (Sandbox Code Playgroud)
1表示尚未布置新鲜的NIB视图.2表示updateConstraints/layoutSubviews什么也没做.3表示将其添加到视图层次结构中什么也没做.4最后表明添加到视图层次结构和一个通过主循环布局的视图.
我希望能够获得视图的尺寸,而不必让应用程序处理它或者自己执行手动计算(字符串高度+约束1 +约束2).
更新
我观察到,如果我放在view里面,UIWindow我会得到一点改善:
UIView *view = [[UINib nibWithNibName:@"View" bundle:nil] instantiateWithOwner:nil options:nil][0];
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
view.frame = CGRectMake(0, 0, 200, 200);
[window addSubview:view];
[view layoutSubviews];
Run Code Online (Sandbox Code Playgroud)
如果view.translatesAutoresizingMaskIntoConstraints == YES,视图的直接子视图将被布局,但他们的孩子都没有.
在您提到的基本情况下,您可以通过调用setNeedsLayout然后layoutIfNeeded在容器视图上获得正确的大小.
使用此方法在绘制之前强制子视图的布局.从接收者开始,只要superviews需要布局,此方法就会向上遍历视图层次结构.然后它展示了祖先下面的整棵树.因此,调用此方法可能会强制整个视图层次结构的布局.UIView的实现调用了等效的CALayer方法,因此具有与CALayer相同的行为.
我不认为"整个视图层次结构"适用于您的用例,因为度量标准视图可能不具有超级视图.
在示例空项目中,仅使用此代码,在layoutIfNeeded调用之后确定正确的帧:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UIView *redView;
@end
@implementation ViewController
@synthesize redView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
redView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 220, 468)];
redView.backgroundColor = [UIColor redColor];
redView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redView];
NSLog(@"Red View frame: %@", NSStringFromCGRect(redView.frame));
// outputs "Red View frame: {{50, 50}, {220, 468}}"
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[redView(==100)]" options:0 metrics:Nil views:NSDictionaryOfVariableBindings(redView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[redView(==100)]" options:0 metrics:Nil views:NSDictionaryOfVariableBindings(redView)]];
NSLog(@"Red View frame: %@", NSStringFromCGRect(redView.frame));
// outputs "Red View frame: {{50, 50}, {220, 468}}"
[self.view setNeedsLayout];
NSLog(@"Red View frame: %@", NSStringFromCGRect(redView.frame));
// outputs "Red View frame: {{50, 50}, {220, 468}}"
[self.view layoutIfNeeded];
NSLog(@"Red View frame: %@", NSStringFromCGRect(redView.frame));
// outputs "Red View frame: {{0, 100}, {100, 100}}"
}
@end
Run Code Online (Sandbox Code Playgroud)
稍微超出了您的问题的范围,这里有一些您可能遇到的其他问题,因为我在一个真实的应用程序中处理了这个确切的问题:
heightForRowAtIndexPath:可能很昂贵,因此您可能需要预先计算并缓存结果estimatedHeightForRowAtIndexPath:以减少这些性能问题的影响intrinsicContentSize回应:
一些子视图里面有东西,
layoutSubviews所以我不能打电话systemLayoutForContentSize:
如果实现intrinsicContentSize,可以使用此方法,这样可以让视图为自己建议最佳大小.一个实现可能是:
- (CGSize) intrinsicContentSize {
[self layoutSubviews];
return CGSizeMake(CGRectGetMaxX(self.bottomRightSubview.frame), CGRectGetMaxY(self.bottomRightSubview.frame));
}
Run Code Online (Sandbox Code Playgroud)
这种简单的方法只有在您的layoutSubviews方法不引用已设置的大小(如self.bounds或self.frame)时才有效.如果是这样,您可能需要执行以下操作:
- (CGSize) intrinsicContentSize {
self.frame = CGRectMake(0, 0, 10000, 10000);
while ([self viewIsWayTooLarge] == YES) {
self.frame = CGRectInset(self.frame, 100, 100);
[self layoutSubviews];
}
return CGSizeMake(CGRectGetMaxX(self.bottomRightSubview.frame), CGRectGetMaxY(self.bottomRightSubview.frame));
}
Run Code Online (Sandbox Code Playgroud)
显然,您需要调整这些值以匹配每个视图的特定布局,并且您可能需要调整性能.
最后,我要补充一点,部分由于使用自动布局的成本呈指数增长,除了最简单的表格单元之外,我通常最终使用手动高度计算.