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];
}
これは自動レイアウトで自動的に行われるべきではありませんか?
[〜#〜]編集[〜#〜]
私の見解の構造は:
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自体には制約がありませんが、親の端に固定することは別です。
Appleのバグを報告した後、この問題を修正しました。マルチラインテキストのレイアウトには2パスアプローチが必要であり、すべてがプロパティpreferredMaxLayoutWidth
に依存しているという問題
マルチラインラベルを含むビューコントローラーに追加する必要がある関連コードは次のとおりです。
- (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];
}
はい、ようやくそれを釘付けにしました。解決策は、preferredMaxLayoutWidth
をviewDidLayoutSubviews
に設定することですが、-afterレイアウトの最初のラウンドのみです。これは、メインスレッドに非同期でディスパッチするだけで調整できます。そう:
- (void)viewDidLayoutSubviews {
dispatch_async(dispatch_get_main_queue(), ^{
self.theLabel.preferredMaxLayoutWidth = self.theLabel.bounds.size.width;
});
}
このようにして、afterになるまでpreferredMaxLayoutWidth
を設定しないでください。ラベルの幅は、スーパービュー関連の制約によって適切に設定されます。
ここでの作業例プロジェクト:
編集:別のアプローチ! UILabelをサブクラス化し、layoutSubviews
をオーバーライドします。
- (void) layoutSubviews {
[super layoutSubviews];
self.preferredMaxLayoutWidth = self.bounds.size.width;
}
結果は自己サイズラベルです。幅がどのように変化しても、その内容に合わせて高さが自動的に変更されます(幅が制約/レイアウトによって変更されている場合)。
Xcode 6.1 for iOS 7/8では、ラベルのテキストを表示するためにビューで呼び出されるセッターメソッドでpreferredMaxLayoutWidth
を設定するだけで、これを機能させることができました。最初は0
に設定されていたと思います。以下の例では、self.teachPieceLabel
がラベルです。ラベルは、Interface Builderのビューで他のラベルと一緒に制約と関連付けられます。
- (void)setTeachPieceText:(NSString *)teachPieceText {
self.teachPieceLabel.text = teachPieceText;
[self.teachPieceLabel setPreferredMaxLayoutWidth:[self.teachPieceLabel bounds].size.width];
}