4

私は自動レイアウトに少し慣れていないので、今行き詰まっています。例を覚えているので、今日 WWDC のビデオを検索しましたが、見つかりませんでした...

シンプルな形式では、レイアウトは次のようになります。

@"|[label]-[value1]-[value2]-[hideDetailsButton]|"
@"V:|[label]|"

ただし、ラベルと hideDetailsButton が上に配置されたままになり、値が複数の行に成長する複数の値を持つことが可能である必要があります。このような:

@"|[label]-[value1]-[value2]-[hideDetailsButton]|"
@"|[value3]-[value4]-[value5]"
@"V:|[label]-[value3]|" 

値ラベルに必要な制約は何ですか?

4

1 に答える 1

4

WWDC 2012 Best Practices for Mastering Auto Layoutを見ると、この動的なサブビューや制約の構築について説明layoutSubviewsされています (ビデオの約 45 分)。これは、適合するビューを追加することに重点を置いていますが、シナリオでも使用できます。

UIViewこれらすべてのラベルを含むコンテナー ビューのサブクラスを作成し、オーバーライドlayoutSubviewsして制約を適切に構成するという考え方です。少し毛むくじゃらですが、機能します:

- (void)layoutSubviews
{
    [super layoutSubviews];

    // add any labels for my `toRecipients` (and add to my dictionary that keeps
    // track of which `UILabel` is for which `toRecipient`)

    for (NSString *toRecipient in self.toRecipients)
    {
        UILabel *label = self.toLabels[toRecipient];
        if (!label)
        {
            label = [[UILabel alloc] init];
            label.text = toRecipient;
            label.translatesAutoresizingMaskIntoConstraints = NO;
            [self addSubview:label];
            [self.toLabels setObject:label forKey:toRecipient];
        }
    }

    // remove any existing constraints on subviews (you could keep track of them and
    // modify them, but I find it just as easy as to start from scratch every time)

    NSMutableArray *constraintsToRemove = [NSMutableArray array];
    for (NSLayoutConstraint *constraint in self.constraints)
    {
        if ([constraint.firstItem superview] == self || [constraint.secondItem superview] == self) {
            [constraintsToRemove addObject:constraint];
        }
    }
    [self removeConstraints:constraintsToRemove];

    // add initial constraints for that leading "To:" label, putting it in the upper left corner

    NSDictionary *views = @{@"to" : self.toLabel};
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[to]" options:0 metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[to]" options:0 metrics:nil views:views]];

    // now let's iterate through the `toRecipients`, and for each one, try adding
    // the label, see where constraints put it (using the label's intrinsic size, too),
    // and if it was too wide, then remove those constraints and add new constraints
    // to put it on the next line

    UIView *previousView = self.toLabel;
    for (NSString *toRecipient in self.toRecipients)
    {
        UIView *nextView = self.toLabels[toRecipient];
        views = NSDictionaryOfVariableBindings(previousView, nextView);
        NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[previousView]-[nextView]" options:0 metrics:nil views:views];
        [self addConstraints:constraints];
        [self updateConstraintsIfNeeded];
        [super layoutSubviews];
        if (CGRectGetMaxX(nextView.frame) < CGRectGetMaxX(self.bounds))
        {
            // if there was room, let's also set the baseline to be the same as the previous item

            [self addConstraint:[NSLayoutConstraint constraintWithItem:nextView attribute:NSLayoutAttributeBaseline relatedBy:NSLayoutRelationEqual toItem:previousView attribute:NSLayoutAttributeBaseline multiplier:1.0 constant:0.0]];
        }
        else
        {
            // otherwise, let's get rid of the constraints I just added and move this next item down to the next line

            [self removeConstraints:constraints];
            [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[nextView]" options:0 metrics:nil views:views]];
            [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[previousView]-[nextView]" options:0 metrics:nil views:views]];
        }

        previousView = nextView;
    }

    // set the bottom constraint for the last recipient

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextView]-|" options:0 metrics:nil views:views]];
    [self updateConstraintsIfNeeded];
    [super layoutSubviews];
}

動的な高さの鍵は、最後の制約です。このUIViewサブクラスを内部のラベルの制約と固有のサイズに基づいてサイズ変更すると、このビューの高さは内部のラベルによって定義されます。このサブクラス化されたビューをメイン ビューに追加するとき、メイン ビューによって定義される上、左、右を定義しますが、下の制約は未定義のままにして、上の最後の制約で高さを定義します。したがって、このサブクラスをメイン ビューに追加すると、次のようになります。

RecipientsView *recipientsView = [[RecipientsView alloc] init];
recipientsView.toRecipients = @[@"rob@frankfurt.de", @"r@berlin.de", @"frank@dusseldorf.de", @"ernest@munich.de", @"mo@cologne.de", @"curly@stuttgart.de"];
recipientsView.backgroundColor = [UIColor lightGrayColor];
recipientsView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:recipientsView];
self.recipientsView = recipientsView;

// set the left, right, and top constraints to the main view, but I'll let the
// intrinsic size of the labels dictate the height of this UIView subclass, RecipientsView

NSDictionary *views = NSDictionaryOfVariableBindings(recipientsView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[recipientsView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[recipientsView]" options:0 metrics:nil views:views]];

[self.view layoutIfNeeded];

背景色を明るい灰色に設定しているので、すべてのラベルとその制約に基づいて高さが動的に設定されていることがわかります。

画面のスナップショット

于 2013-08-20T03:39:38.170 に答える