web-dev-qa-db-ja.com

iOS:自動レイアウトの複数行UILabel

自動レイアウトを使用して、非常に基本的なレイアウト動作を実現しようとして問題が発生しています。私のView ControllerはIBでは次のようになります:

enter image description here

トップラベルはタイトルラベルです。何行になるかわかりません。すべてのテキスト行を表示するにはタイトルラベルが必要です。また、他の2つのラベルと小さな画像をタイトルの真下にレイアウトする必要がありますが、たまたま高さがあります。ラベルと小さな画像の間に垂直方向の間隔の制約を設定し、タイトルラベルとそのスーパービューの間に上部の間隔の制約、小さな画像とそのスーパービューの間に下部の間隔の制約を設定しました。白いUIViewには高さの制約がないため、サブビューを含めるために垂直に伸びる必要があります。タイトルラベルの行数を0に設定しました。

文字列に必要な行数に合わせてタイトルラベルのサイズを変更するにはどうすればよいですか?私の理解では、自動レイアウトを使用しているため、setFrameメソッドを使用できません。また、他のビューがタイトルラベルの下にとどまる必要があるため、自動レイアウトを使用する必要があります(したがって制約があります)。

どうすればこれを実現できますか?

177
James Harpe

UILabel-setPreferredMaxLayoutWidthを使用すると、自動レイアウトが残りを処理するはずです。

[label setPreferredMaxLayoutWidth:200.0];

preferredMaxLayoutWidthのUILabelドキュメント を参照してください。

更新:

ストーリーボードの高さの制約を「以上」に設定するだけで、setPreferredMaxLayoutWidthは不要です。

248
mwhuss

ラベルセットの行数を0に展開し、さらに重要な自動レイアウトセットの高さをx以上にします。自動レイアウトが残りを行います。また、前の要素に基づいて他の要素を含めて、適切に配置することもできます。

auto layout

210
Charlie Wu

ソース: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

複数行テキストの本質的なコンテンツサイズ

UILabelとNSTextFieldの本質的なコンテンツサイズは、複数行のテキストではあいまいです。テキストの高さは、線の幅に依存しますが、これは制約を解決するときにまだ決定されていません。この問題を解決するために、両方のクラスにpreferredMaxLayoutWidthと呼ばれる新しいプロパティがあります。このプロパティは、固有のコンテンツサイズを計算するための最大行幅を指定します。

通常、この値は事前にわからないため、これを正しく行うには2段階のアプローチが必要です。最初に自動レイアウトを機能させてから、レイアウトパスで結果のフレームを使用して、優先最大幅を更新し、レイアウトを再度トリガーします。

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

[super layoutSubviews]の最初の呼び出しは、ラベルがフレームセットを取得するために必要であり、2番目の呼び出しは、変更後にレイアウトを更新するために必要です。 2番目の呼び出しを省略すると、NSInternalInconsistencyExceptionエラーが発生します。これは、レイアウトパスに変更を加えて制約の更新が必要になったため、レイアウトを再度トリガーしなかったためです。

ラベルサブクラス自体でこれを行うこともできます。

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

この場合、最初に[super layoutSubviews]を呼び出す必要はありません。layoutSubviewsが呼び出されると、ラベル自体にフレームが既にあるからです。

View Controllerレベルからこの調整を行うには、viewDidLayoutSubviewsにフックします。この時点で、最初の自動レイアウトパスのフレームは既に設定されており、それらを使用して優先最大幅を設定できます。

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

最後に、ラベルのコンテンツ圧縮抵抗優先度よりも優先度の高い明示的な高さ制限がラベルにないことを確認してください。そうでなければ、計算されたコンテンツの高さよりも優先されます。ラベルの高さに影響を与える可能性のあるすべての制約を必ず確認してください。

44
Anton Matosov

私はちょうどこの正確なシナリオと戦っていましたが、必要に応じてサイズを変更したり下に移動したりする必要があるビューがかなり多くありました。それは私を夢中にさせていましたが、私はついにそれを理解しました。

重要な点は次のとおりです。InterfaceBuilderは、ビューを追加および移動するときに余分な制約を追加することを好みますが、気づかないかもしれません。私の場合、ビューとそのスーパービューの間のサイズを指定する追加の制約があり、基本的にそのポイントに固定されているビューが半分下がっていました。つまり、その制約に反するため、それより上のサイズは大きく変更できません。

これが事実かどうかを確認する簡単な方法は、ラベルのサイズを手動で変更することです。 IBは成長させますか?もしそうなら、下のラベルは期待通りに動きますか?サイズを変更する前にこれらの両方をチェックして、制約がビューをどのように移動するかを確認してください。

IB Menu

ビューがスタックしている場合は、その下にあるビューに従って、ビューの1つにスーパービュー制約の上部スペースがないことを確認します。次に、ラベルの行数オプションが0に設定されていることを確認するだけで、残りは処理されます。

16
Cory Imdieke

次のものが必要だと思います。

  • 上部の制約
  • 先行する制約(左側など)
  • 末尾の制約(右側など)
  • コンテンツのハグの優先度を水平から低に設定し、テキストが短い場合に指定されたスペースを埋めます。
  • コンテンツの圧縮抵抗を水平から低に設定し、幅を広げようとせずに折り返すようにします。
  • 行数を0に設定します。
  • 改行モードをワードラップに設定します。
5
Chris

主題に関する多くのトピックで見つかったさまざまなソリューションはどれも、私の場合(動的テーブルビューセルのx動的マルチラインラベル)に完全に機能しませんでした。

私はそれを行う方法を見つけました:

ラベルに制約を設定し、マルチラインプロパティを0に設定した後、UILabelのサブクラスを作成します。私はAutoLayoutLabelを呼び出しました:

@implementation AutoLayoutLabel

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

@end
0
Tanguy G.

テキストラップラベルを持つUITableViewCellがあります。次のようにテキストの折り返しを行いました。

1)次のようにUILabel制約を設定します。

enter image description here

2)セット番号0行まで。

3)UITableelCellにUILabelの高さの制約を追加しました。

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4)UITableViewCellの場合:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
0
A.G