创建一个基于自动版式的指标视图 [英] Creating an autolayout-based metrics view

查看:133
本文介绍了创建一个基于自动版式的指标视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我将使用在的UITableViewCell的 UICollectionViewCell 的可重复使用的视图,并且需要得到它的为尺寸的tableView:heightForRowAtIndexPath:。一些子视图都去的东西里面 layoutSubviews 所以我不能叫 systemLayoutForContentSize:,而不是我的计划是:

I have a reusable view I will be using in UITableViewCell's and UICollectionViewCell's, and need to get its dimensions for tableView:heightForRowAtIndexPath:. Some subviews have stuff going on inside layoutSubviews so I can't call systemLayoutForContentSize:, instead my plan is to:


  1. 实例化指标视图。

  2. 设置大小,包括所需的宽度。

  3. 填充数据。

  4. 更新限制/布局子视图。

  5. 抢视图或一个内部上浆的观点的高度。

我遇到的问题是,我不能强迫视图布局,而不将其插入视图,并等待runloop。

The problem I'm running into is that I cannot force the view to layout without inserting it into the view and waiting for the runloop.

我蒸馏相当沉闷的例子。这里是View.xib。该子视图对齐,以突出的观点是永远不会得到奠定了甚至到了基线位置:

I've distilled a rather boring example. Here's View.xib. The subview is misaligned to highlight that the view is never getting laid out even to the baseline position:

在主线程我打电话:

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);
});

我得到了以下视图的信息:

I get out the following view information:

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>>"

1表明新鲜出的最NIB视图尚未布置。 2显示 updateConstraints / layoutSubviews 什么也没做。 3表明,将它添加到视图层次也没做。 4最后指出,将通过主回路的视图层次,一个传中规定的看法。

1 indicates that the fresh-out-of-the-NIB view hasn't been laid out. 2 indicates that updateConstraints/layoutSubviews did nothing. 3 indicates that adding it to the view hierarchy did nothing. 4 finally indicates that adding to the view hierarchy and one pass through the main-loop laid out the view.

我想获得的地步,我可以得到视图的尺寸,而无需让应用程序处理它还是我自己执行手动计算(弦高+ constraint1 + constraint2)。

I would like to get to the point where I can get the view's dimensions without having to let the application handle it or perform manual calculations (string height + constraint1 + constraint2) on my own.

更新

我认为,如果我把视图的UIWindow 我得到一个略有改善:

I've observed that if I place view inside a UIWindow I get a slight improvement:

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];

如果 view.translatesAutoresizingMaskIntoConstraints == YES ,视图的子视图直接将摆出来,但没有自己的孩子。

If view.translatesAutoresizingMaskIntoConstraints == YES, the view's immediate subviews will be laid out, but none of their children.

推荐答案

在你提到的基本情况,你可以通过调用 setNeedsLayout ,然后得到正确的尺寸 layoutIfNeeded 的容器视图。

The Autolayout Question

In the basic case you mentioned, you can get the correct size by calling setNeedsLayout and then layoutIfNeeded on the container view.

从<一个href=\"https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/instm/UIView/layoutIfNeeded\">UIView在 layoutIfNeeded 类参考:

使用此方法强制子视图的布局绘制前。与接收器开始,这种方法向上通过视图层次只要superviews需要遍历布局。然后,它勾画出了祖先下的整个树。因此,调用此方法可能会迫使整个视图层次的布局。这样做的UIView的实现调用相当于CALayer的方法等方面具有相同的行为CALayer的。

Use this method to force the layout of subviews before drawing. Starting with the receiver, this method traverses upward through the view hierarchy as long as superviews require layout. Then it lays out the entire tree beneath that ancestor. Therefore, calling this method can potentially force the layout of your entire view hierarchy. The UIView implementation of this calls the equivalent CALayer method and so has the same behavior as CALayer.

我不认为整个视图层次适用于您的使用情况下,由于指标查看presumably不会有上海华。

I don't think the "entire view hierarchy" applies to your use case since the metrics view presumably wouldn't have a superview.

在样本空项目,只有这code,正确的框架后, layoutIfNeeded 确定被称为:

In a sample empty project, with just this code, the correct frame is determined after layoutIfNeeded is called:

#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

其他注意事项

微微外展你的问题的范围,这里有您可能会遇到其他一些问题,因为我在一个真正的应用程序在这个确切的问题的工作:

Additional Considerations

Slightly outside the scope of your question, here are some other issues you may run into, since I've worked on this exact problem in a real app:


  • 这样计算下来heightForRowAtIndexPath:可能是昂贵的,所以你可能要precalculate和缓存结果

  • precalculation应该在后台线程来完成,但是UIView的布局不能很好地工作,除非它在主线程上执行

  • 您一定要落实 estimatedHeightForRowAtIndexPath:来减少这些性能问题的影响

  • Calculating this in heightForRowAtIndexPath: might be expensive, so you may want to precalculate and cache the results
  • Precalculation should be done on a background thread, but UIView layout doesn't work well unless it's done on the main thread
  • You should definitely implement estimatedHeightForRowAtIndexPath: to reduce the impact of these performance issues

在回应:

一些子视图有东西要去里面 layoutSubviews 所以我不能叫 systemLayoutForContentSize:

Some subviews have stuff going on inside layoutSubviews so I can't call systemLayoutForContentSize:

如果您实施 intrinsicContentSize ,它可以让一个观点建议的最佳大小本身您可以使用此方法。这其中的一个实现可能是:

You can use this method if you implement intrinsicContentSize, which lets a view suggest an optimal size for itself. One implementation for this might be:

- (CGSize) intrinsicContentSize {
    [self layoutSubviews];
    return CGSizeMake(CGRectGetMaxX(self.bottomRightSubview.frame), CGRectGetMaxY(self.bottomRightSubview.frame));
}

这个简单的方法将只有当你的工作 layoutSubviews 方法并不是指一个已经集大小(如 self.bounds self.frame )。如果是这样,你可能需要做这样的事情:

This simple approach will only work if your layoutSubviews method doesn't refer to an already-set size (like self.bounds or self.frame). If it does, you may need to do something like:

- (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));
}

显然,你需要调整这些值以满足每个视图的具体布局,您可能需要调整性能。

Obviously, you'd need to adjust these values to match the particular layout of each view, and you may need to tune for performance.

最后,我要补充一点,部分原因是由于在成倍增加成本使用自动布局,为所有,但最简单的表格单元格中,我通常风采用手动高度计算。

Finally, I'll add that due in part to the exponentially increasing cost of using auto-layout, for all but the simplest table cells, I usually wind up using manual height calculation.

这篇关于创建一个基于自动版式的指标视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆