UILabel sizeToFitがautolayout iOS6で機能しない


152

高さがテキストに依存するUILabelをプログラムで(およびどのメソッドで)構成する必要がありますか?Storyboardとコードの組み合わせを使用して設定しようとしていますが、役に立ちません。誰もが推奨していますsizeToFit設定中lineBreakModenumberOfLines。しかし、どんなに私がでそのコードを入れた場合viewDidLoad:viewDidAppear:またはviewDidLayoutSubviews私は仕事にそれを得ることができません。長いテキストに対してボックスを小さくしすぎて大きくならないか、大きくしすぎて縮小しません。


同じコードをFWIW:label.sizeToFit()Xcode / viewControllerで使用する必要はありませんでした。制約は十分でした。Playgroundでラベルを作成していませんでした。これまでのところ、プレイグラウンドで動作するように私が見つけた唯一の方法は、実行することですlabel.sizeToFit()
ハニー

回答:


407

ほとんどの場合、Mattのソリューションは期待どおりに機能することに注意しください。それでもうまくいかない場合は、さらに読んでください。

ラベルの高さを自動的に変更するには、次の操作を行う必要があります。

  1. ラベルのレイアウト制約を設定する
  2. 低優先度で高さ制約を設定します。ContentCompressionResistancePriorityより低くする必要があります
  3. numberOfLines = 0に設定します
  4. ContentHuggingPriorityをラベルの高さの優先度よりも高く設定します
  5. ラベルのpreferredMaxLayoutWidthを設定します。ラベルはその値を使用して高さを計算します

例えば:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

Interface Builderの使用

  1. 4つの制約を設定します。高さの制約は必須です。 ここに画像の説明を入力してください

  2. 次に、ラベルの属性インスペクターに移動して、行数を0に設定します。 ここに画像の説明を入力してください

  3. ラベルのサイズインスペクターに移動し、垂直方向のContentHuggingPriorityと垂直方向のContentCompressionResistancePriorityを増やします。
    ここに画像の説明を入力してください

  4. 高さの制約を選択して編集します。
    ここに画像の説明を入力してください

  5. また、高さ制約の優先度を下げます。
    ここに画像の説明を入力してください

楽しい。:)


4
はい!これがまさに私が探していた答えです。私がする必要があるのは、contentHuggingPriorityとcontentCompressionResistancePriorityをrequiredに設定することだけでした。すべてIBでできる!どうもありがとうございます。
Circuitlego 2013

43
あなたはこれを考えすぎています。設定するpreferredMaxLayoutWidthか、ラベルの幅(またはその右側と左側)を固定します。それで全部です!次に、コンテンツに合わせて垂直方向に自動的に拡大および縮小します。
マット

preferredMaxLayoutWidthプロパティを設定して、ラベルの幅を固定する必要がありました。魅力のように動作します:)
MartinMoizard 2013年

preferredMaxLayoutWidthおよび/または左側と右側の固定は絶対的なものではありません。コンテンツのハグと圧縮の優先度は、優先度が他の制約よりも高い限り、常に機能します。
Eric Alford 2015年

2
^そして最後に、なぜかを確認します。セルがビューの下部にくっついている場合、「下部へ」制約の優先度を1000未満に設定する必要があります。750に設定して、すべてが完璧に機能しています。見た目が縮小したようです。
Mathijs Segers、2015年

65

iOS 6では、autolayoutを使用して、UILabelの側面(または幅)と上部が固定されている場合、コンテンツに合わせて自動的に垂直方向に拡大および縮小します。コードはまったくなく、圧縮抵抗などをいじる必要ありません。とても簡単です。

より複雑なケースでは、ラベルを設定するだけpreferredMaxLayoutWidthです。

どちらにしても、正しいことが自動的に行われます。


12
また、numberOfLinesを必ず0に設定する必要があります。そうしないと、折り返されません。
devongovett 2013

2
これでは十分ではありませんでした。@Markの回答のポイント2も必要です。
Danyal Aytekin 2013

コードを書かなくてもラベルを自動的に数行に拡大させることは可能ですか?
Noor、

これは、受け入れられた回答よりもはるかに複雑ではありません。私はこの答えを説明する 2つの例(ここここ)を作成しました。
Suragch

@Suragch制約を使用してこれは機能します。ただし、Playgroundの同じコードは機能しません。プレイグラウンドでは、あなたが持っている必要がありますlabel.sizeToFit()
ハニー

42

質問はプログラムで述べられており、同じ問題が発生し、Interface Builderで作業することを望んでいますが、Interface Builderソリューションを使用して既存の回答に追加すると便利だと思いました。

最初のことは忘れることsizeToFitです。自動レイアウトは、固有のコンテンツサイズに基づいてこれを処理します。

したがって、問題は、自動レイアウトを使用してラベルをそのコンテンツに合わせる方法を教えてください。具体的には-質問が言及しているため-高さ。同じ原則が幅にも適用されることに注意してください。

それでは、高さを41pxに設定したUILabelの例から始めましょう。

ここに画像の説明を入力してください

上の画面でわかる"This is my text"ように、上下にパディングがあります。これは、UILabelの高さとそのコンテンツであるテキストの間のパディングです。

アプリをシミュレーターで実行すると、確かに同じことがわかります。

ここに画像の説明を入力してください

次に、Interface BuilderでUILabelを選択して、サイズインスペクターのデフォルト設定を見てみましょう。

ここに画像の説明を入力してください

上記の強調表示された制約に注意してください。それがコンテンツハグの優先事項です。Erica Sadunが優れたiOS Auto Layout Demystifiedで説明しているように、これは次のとおりです。

ビューがコアコンテンツの周りの余分なパディングを避けることを好む方法

私たちにとって、UILabelでは、コアコンテンツはテキストです。

ここで、この基本的なシナリオの中心に来ます。テキストラベルに2つの制約を与えました。彼らは対立します。ある人は、「高さは41ピクセルの高さに等しくなければならない」と言っています。もう1つは、「コンテンツのビューをハグして、余分なパディングがないようにする」です。私たちの場合、ビューをテキストにハグして、余分なパディングがないようにします。

さて、自動レイアウトでは、異なることを行う2つの異なる命令により、ランタイムはどちらか一方を選択する必要があります。両方はできません。UILabelを41ピクセルの高さにしたり、パディングを入れたりすることはできません。

これを解決する方法は、優先順位を指定することです。1つの命令は、他の命令よりも優先度が高くなければなりません。両方の命令が異なることを言い、優先順位が同じである場合、例外が発生します。

だからそれをやってみましょう。高さの制約の優先度は1000で、これは必須です。内容を抱き締める高さは250で弱いです。高さ制約の優先度を249に下げるとどうなりますか?

ここに画像の説明を入力してください

これで魔法の始まりがわかります。シムで試してみましょう:

ここに画像の説明を入力してください

驚くばかり!コンテンツハグを達成しました。高さ優先度249がコンテンツハグ優先度250よりも低いためです。基本的に、「ここで指定する高さは、コンテンツをハグするために指定した高さよりも重要ではありません」と言っています。だから、コンテンツをハグして勝つ。

要点は、ラベルをテキストに合わせて取得するには、高さまたは幅の制約を指定するだけでよく、その軸のコンテンツハグの優先順位制約に関連してその優先順位を正しく設定します。

読者のための練習として、幅に相当することを行います!


3
素晴らしい説明ありがとうございました!最後に、コンテンツハグの優先度について理解しました。
kernix 14

コンテンツ圧縮耐性の優先度とは何ですか?ありがとう!
kernix 2014年

2
ExcelenteがMaxに回答します。そのように機能する行の数を制限する方法はありますか?
rafaeljuzo 2014年

7

IOS7で気付いたsizeToFitも機能していなかった-おそらくこのソリューションも役立つかもしれません

[textView sizeToFit];
[textView layoutIfNeeded];

1
@Rambatinoこれは私には有効です。layoutIfNeeded必要なときに追加しますsetNeedsUpdateConstraints。しかし、状況は少し異なる場合があります。
2014年

私がポップオーバーをしたとき、これは私にとって最もうまくいきました。ただし、最初にlayoutIfNeededを実行する必要がありました
Jason

4

ラベルのpreferredMaxLayoutWidthをラベルの幅と同期させるための別のオプション:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end

4

適切な解決策を見つけるのにしばらく時間がかかったので、私は貢献すべきだと思います。

  • 目標は、sizeToFit()を呼び出さずに自動レイアウトが機能するようにすることです。これを行うには、適切な制約を指定します。
  • UILabelで上部、下部、および先頭/末尾のスペース制約を指定する
  • 行数プロパティを0に設定します。
  • コンテンツハグの優先度を1000に増やす
  • コンテンツの圧縮耐性の優先度を500に下げる
  • 下のコンテナ制約で、優先度を500に下げます

基本的に何が起こるかというと、UILabelに固定高さの制約があっても、コンテンツをハグするために制約を解除してそれ自体を小さくできる(たとえば、1行の場合)が、それができないことです。制約を解除して大きくします。


3

私の場合、UILabel(長さが不明)を含むUIViewサブクラスを作成していました。iOS7では、コードは簡単でした。制約を設定し、コンテンツのハグや圧縮の耐性について心配しないでください。すべてが期待どおりに機能しました。

しかしiOS6では、UILabelは常に1行にクリップされていました。上記の答えはどれもうまくいきませんでした。コンテンツハグと圧縮耐性の設定は無視されました。クリッピングを防ぐ唯一の解決策は、ラベルにpreferredMaxLayoutWidthを含めることでした。しかし、親ビューのサイズが不明だったため、適切な幅を何に設定するかわかりませんでした(実際、内容によって定義されます)。

私は最終的にここで解決策を見つけました。私はカスタムビューで作業していたため、次のメソッドを追加して、制約が1回計算された後に優先レイアウト幅を設定し、それらを再計算することができます。

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}

これは私が持っていた正確なシナリオでした…あなたが一人ではないことを知っているのは良いことです。
daveMac 2014年

アダム、私はあなたがios7で完全に機能したと言っていることに苦労しています。uiviewとuilabelを持つカスタムセルがあります。ラベルをコンテンツに合わせることができますが、どのような制約を課しても、ビューはそうではありません。どのように機能させましたか?私はすべてを試したと誓いますが、それはレーベルの高さを
反映し

3

私はUILabelプログラムで追加し、私の場合はそれで十分でした:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0

2

xCode6で「Preferred Width」を自動に設定して解決し、ラベルの上部、先頭、末尾をピン留めしました ここに画像の説明を入力してください


0
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));

0

この問題に遭遇したのは、UILabelが内部要素の場合と同じように含まれているUIViewサブクラスでした。自動レイアウトを使用して、推奨されるすべての解決策を試しても、ラベルはテキストに合わせて高さを調整しませんでした。私の場合、ラベルを1行にするだけです。

とにかく、私にとってうまくいったことは、UILabelに必要な高さの制約を追加し、intrinsicContentSizeが呼び出されたときに手動で正しい高さに設定することでした。UILabelが別のUIViewに含まれていない場合は、UILabelをサブクラス化して、最初に高さの制約を設定してから
[super instrinsicContentSize]を返すことで同様の実装を提供できます。[self.containerview組み込みeContentSize]の代わりに; 以下のように、これは私のUIViewサブラスに固有のものです。

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

iOS 7およびiOS 8で完全に動作します。


ビューを正しく設定した場合(つまり、制約が正しく、ビューのライフサイクルの適切な段階ですべてを設定した場合)、オーバーライドする必要はないことに注意してくださいintrinsicContentSize。ランタイムは、正しく設定された制約に基づいてこれを計算できるはずです。
John Rogers

理論的にはそれは正しいはずですが、AppleのプライベートAPIと実装のすべてにアクセスできるわけではなく、それらは完全なものではなく、コードにバグがあります。
n8tr 2015年

...しかし、[super explicitContentSize]がそれを処理する必要があると私は言っています。自動レイアウトを正しく実装した場合。
John Rogers

0

私のために働いた解決策; UILabelの幅が固定されている場合は、インターフェースファイルの制約をからconstant =に変更しconstant <=ます

ここに画像の説明を入力してください


-1

私の場合、UITableViewCellでラベルを使用すると、ラベルのサイズは変更されますが、高さがテーブルのセルの高さを超えてしまいます。これは私のために働いたものです。Max MacLeodによると、セルの高さがUITableViewAutomaticDimensionに設定されていることを確認しました。

これをinitまたはawakeFromNibに追加できます。

self.tableView.rowHeight = UITableViewAutomaticDimension.  

ストーリーボードでセルを選択し、サイズインスペクタを開いて、[カスタム]チェックボックスをオフにして、行の高さが「デフォルト」に設定されていることを確認します。

8.0にも問題があり、コードで設定する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.