30

UILabel のみを含むビューがあります。このラベルには複数行のテキストが含まれています。親には、パン ジェスチャでサイズ変更できる可変幅があります。私の問題は、このサイズ変更を行うと、すべてのコンテンツがまだ表示されるように UILabel の高さが再計算されず、単に切り取られることです。

ちょっとしたハックでなんとか修正できましたが、実行が非常に遅いです。

- (void)layoutSubviews {

    CGSize labelSize = [self.labelDescription sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

    if (self.constraintHeight) {
        [self removeConstraint:self.constraintHeight];
    }

    self.constraintHeight = [NSLayoutConstraint constraintWithItem:self.labelDescription attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:labelSize.height];

    [self addConstraint:self.constraintHeight];

    [super layoutSubviews];
}

これは autolayout で自動的に起こるべきではありませんか?

編集

私のビューの構造は次のとおりです。

UIScrollView
---> UIView
     ---> UILabel

UIScrollView の制約は次のとおりです。

<NSLayoutConstraint:0x120c4860 H:|-(>=32)-[DescriptionView:0x85c81c0]   (Names: '|':UIScrollView:0x85db650 )>,
<NSLayoutConstraint:0x120c48a0 H:|-(32@900)-[DescriptionView:0x85c81c0] priority:900   (Names: '|':UIScrollView:0x85db650 )>,
<NSLayoutConstraint:0x120c48e0 H:[DescriptionView:0x85c81c0(<=576)]>,
<NSLayoutConstraint:0x120c4920 H:[DescriptionView:0x85c81c0]-(>=32)-|   (Names: '|':UIScrollView:0x85db650 )>,
<NSLayoutConstraint:0x120c4960 H:[DescriptionView:0x85c81c0]-(32@900)-| priority:900   (Names: '|':UIScrollView:0x85db650 )>,
<NSLayoutConstraint:0x8301450 DescriptionView:0x85c81c0.centerX == UIScrollView:0x85db650.centerX>,

UIView の制約は次のとおりです。

<NSLayoutConstraint:0x85c4580 V:|-(0)-[UILabel:0x85bc7b0]   (Names: '|':DescriptionView:0x85c81c0 )>,
<NSLayoutConstraint:0x85c45c0 H:|-(0)-[UILabel:0x85bc7b0]   (Names: '|':DescriptionView:0x85c81c0 )>,
<NSLayoutConstraint:0x85c9f80 UILabel:0x85bc7b0.trailing == DescriptionView:0x85c81c0.trailing>,
<NSLayoutConstraint:0x85c9fc0 UILabel:0x85bc7b0.centerY == DescriptionView:0x85c81c0.centerY>

UILabel 自体には、親の端に固定することを除いて、制約はありません

4

3 に答える 3

40

さて、私はついにそれを釘付けにしました。preferredMaxLayoutWidth解決策はinを設定することですが、レイアウトの最初のラウンドのviewDidLayoutSubviewsでのみです。これは、メイン スレッドに非同期でディスパッチするだけで簡単に調整できます。そう:

- (void)viewDidLayoutSubviews {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.theLabel.preferredMaxLayoutWidth = self.theLabel.bounds.size.width;
    });
}

そうすれば、スーパービュー関連の制約によってラベルの幅が適切に設定されるまでpreferredMaxLayoutWidth設定しません。

ここでの作業例プロジェクト:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch23p673selfSizingLabel4/p565p579selfSizingLabel/ViewController.m

編集:別のアプローチ!UILabel をサブクラス化し、オーバーライドしますlayoutSubviews

- (void) layoutSubviews {
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

その結果、セルフサイズのラベルが作成されます。幅がどのように変化しても、コンテンツに合わせて高さが自動的に変更されます (幅が制約/レイアウトによって変更されると仮定します)。

于 2012-11-28T23:08:28.763 に答える
26

Appleでバグを提起した後、この問題を修正しました。複数行のテキストはレイアウトに2パスのアプローチが必要であり、すべてがプロパティに依存しているという問題preferredMaxLayoutWidth

複数行のラベルを含むViewControllerに追加する必要のある関連コードは次のとおりです。

- (void)viewWillLayoutSubviews
{
    // Clear the preferred max layout width in case the text of the label is a single line taking less width than what would be taken from the constraints of the left and right edges to the label's superview
    [self.label setPreferredMaxLayoutWidth:0.];
}

- (void)viewDidLayoutSubviews
{
    // Now that you know what the constraints gave you for the label's width, use that for the preferredMaxLayoutWidth—so you get the correct height for the layout
    [self.label setPreferredMaxLayoutWidth:[self.label bounds].size.width];

    // And then layout again with the label's correct height.
    [self.view layoutSubviews];
}
于 2012-11-19T04:09:43.800 に答える