使用程序化自动布局时,Container View的框架设置为CGRectZero

时间:2015-06-19 02:04:35

标签: ios objective-c uiview uiviewcontroller autolayout

我有一个UIView子类,它将是一个工具提示,可以出现在任何视图控制器的底部,以显示提示/错误消息/成功消息/等。工具提示视图有两个子视图:左侧是UILabel,右侧是UIView,可以是任何内容(但通常用作UIButton)。

TooltipView.h

@interface TooltipView : UIView

@property (nonatomic, readonly) UILabel *textLabel;

@property (nonatomic) UIView *rightView;

TooltipView.m

static CGFloat const kSubviewToSuperviewSpacing = 7.0f;
static CGFloat const kTextLabelToRightViewHorizontalSpacing = 7.0f;

@implementation TooltipView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        _textLabel = [[UILabel alloc] init];
        _textLabel.numberOfLines = 0;
        [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];

        [self addSubview:_textLabel];
    }

    return self;
}

- (void)setRightView:(UIView *)rightView {
    if (_rightView != rightView) {
        _rightView = rightView;

        [self addSubview:_rightView];

        [self setNeedsDisplay];
    }
}

- (BOOL)translatesAutoresizingMaskIntoConstraints {
    return NO;
}

- (void)updateConstraints {
    self.didUpdateConstraints = YES;

    [self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel
                                                     attribute:NSLayoutAttributeLeading
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self
                                                     attribute:NSLayoutAttributeLeading
                                                    multiplier:1.0f
                                                      constant:kSubviewToSuperviewSpacing]];

    NSMutableDictionary *metricsDictionary = [@{@"subviewToSuperviewSpacing": @(kSubviewToSuperviewSpacing)} mutableCopy];

    NSMutableDictionary *viewsDictionary = [@{@"textLabel": self.textLabel} mutableCopy];

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-subviewToSuperviewSpacing-[textLabel]-subviewToSuperviewSpacing-|"
                                                                 options:0
                                                                 metrics:metricsDictionary
                                                                   views:viewsDictionary]];

    if (self.rightView) {
        metricsDictionary[@"textLabelToRightViewHorizontalSpacing"] = @(kTextLabelToRightViewHorizontalSpacing);
        viewsDictionary[@"rightView"] = self.rightView;

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-subviewToSuperviewSpacing-[rightView]-subviewToSuperviewSpacing-|"
                                                                     options:0
                                                                     metrics:metricsDictionary
                                                                       views:viewsDictionary]];

        [self addConstraint:[NSLayoutConstraint constraintWithItem:self.rightView
                                                         attribute:NSLayoutAttributeTrailing
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:self
                                                         attribute:NSLayoutAttributeTrailing
                                                        multiplier:1.0f
                                                          constant:kSubviewToSuperviewSpacing]];
    }

    [super updateConstraints];
}

我还有一个视图控制器,可以使用UILabel作为rightView进行测试。它是UIViewController的子类,它唯一的方法是覆盖loadView

- (void)loadView {
    TooltipView *tooltipView = [[TooltipView alloc] initWithFrame:CGRectZero];

    tooltipView.textLabel.text = @"Test 1";

    UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    testLabel.text = @"Hello there";
    [testLabel setTranslatesAutoresizingMaskIntoConstraints:NO];

    tooltipView.rightView = testLabel;

    self.view = tooltipView;

}

最后,在我想要显示工具提示的视图控制器中,我将TooltipViewController添加为子视图控制器。最终,这将由某些事件触发,但出于测试目的,我将其添加到viewWillAppear:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    self.aViewController = [[TooltipViewController alloc] init];
    self.aViewController.view.backgroundColor = [UIColor whiteColor];

    [self addChildViewController:self.aViewController];

    [self.view addSubview:self.aViewController.view];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:@{@"view": self.aViewController.view}]];

    [self.aViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:self.aViewController.view
                                                      attribute:NSLayoutAttributeHeight
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:nil
                                                      attribute:NSLayoutAttributeNotAnAttribute
                                                     multiplier:1.0f
                                                       constant:150.0f]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.aViewController.view
                                                      attribute:NSLayoutAttributeBottom
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeBottom
                                                     multiplier:1.0f
                                                       constant:0.0f]];

    [self.aViewController didMoveToParentViewController:self];
}

但是,在运行时,textLabelrightView的帧似乎设置正确,但tooltipView的帧设置为CGRectZero,没有这三个视图出现在屏幕上。

提前致谢!

修改

我甚至试图完全删除textLabelrightView,所以只是一个简单的UIView,包含前导,尾随,底部和高度限制。没有什么是模糊的,但视图的框架仍然是CGRectZero

2 个答案:

答案 0 :(得分:7)

事实证明,解决方案只是在setTranslatesAutoresizingMaskIntoConstraints的初始化程序中调用TooltipView而不是覆盖该方法。这导致视图正确显示。致Haron Thompson(https://twitter.com/aaptho/status/612815498661773312)。

答案 1 :(得分:1)

您似乎错过了与textLabelrightView相关的约束。查看您的-updateConstraints实现,我认为最终的约束可以表示为:

V:|-kSubviewToSuperviewSpacing-[textLabel]-kSubviewToSuperviewSpacing-|
V:|-kSubviewToSuperviewSpacing-[rightView]-kSubviewToSuperviewSpacing-|
H:|-kSubviewToSuperviewSpacing-[textLabel]
H:[rightView]-kSubviewToSuperviewSpacing-|

如果您在if (self.rightView)内添加约束关系:

[self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel
                                                     attribute:NSLayoutAttributeTrailing
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self.rightView
                                                     attribute:NSLayoutAttributeLeading
                                                    multiplier:1.0f
                                                      constant: kTextLabelToRightViewHorizontalSpacing]];

然后添加else子句:

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[textLabel]-subviewToSuperviewSpacing-|"
                                                             options:0
                                                             metrics:metricsDictionary
                                                               views:viewsDictionary]];

您将有足够的约束来明确定义布局。这应该在superview中触发基于约束的自动调整大小。

如果这不起作用,您应该考虑覆盖-intrinsicContentSize方法并返回textLabelrightView及其填充的intrinsicContentSize&#39。您需要在-invalidateIntrinsicContentSize中致电-setRightView:才能使其正常运行。

作为次要问题,您未在-updateConstraints中清除任何约束,因此在调用此视图的约束更新过程中,您将获得双重约束。您可能希望将部分约束创建移至-init,然后根据需要仅在textLabel中添加/删除rightView-updateConstraints关系。