UILabel に入れたタイトルがあります。テキストを 2 行にうまく折り返すことができますが、多くの場合、2 行目には小さな単語が 1 つだけ含まれています。行をもう少し均等に折り返すようにシステムに指示する方法はありますか?
タイトルは動的に取得されるため、これを事前に決定できるとは思えません。
1 行の長さを計算し、その幅を 2 で割り、その結果を 2 行のラベルの幅制約として使用できます。これにより、視覚的な結果が向上する可能性がありますが、ラベルが 3 行になる長い単語がある場合は、これを少し調整する必要があるかもしれません (2 行以上が問題ない場合を除く)。
このアプローチには、少し余分な作業を行うという欠点がありますが、うまくいく可能性があります。例えば:
NSString *text = @"これは私の非常に長いタイトルで、均等に 2 行にしたい"; UILabel *theLabel = [[UILabel alloc] init]; theLabel.text = テキスト; // ...フォントなどの他のラベル設定 [theLabel sizeToFit]; CGSize 制約 = CGSizeMake(theLabel.frame.size.width / 2.0, 1000); CGSize labelSize = [theLabel.text sizeWithFont:theLabel.font constraintToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; theLabel.numberOfLines = 0; theLabel.lineBreakMode = UILineBreakModeWordWrap; CGRect フレーム = theLabel.frame; frame.size = labelSize; theLabel.frame = フレーム;
それはそれを行う必要があります。警告: メモリから書き込まれます。:-)
これを行う簡単な方法はないと思います。NSString
特定のフォントで文字列を表示するために必要なサイズを決定できるUIKit の追加があります。できることは、使用可能なすべての幅を使用して必要な高さを計算し、同じ計算をループで実行して、追加の垂直スペースが必要になるまで幅を減らすことです。次に、前の値をラベルの幅として使用し、適切に配置します。
多言語アプリの場合、これとまったく同じ問題も修正する必要がありました。アプリは 9 つの異なる言語で UI を表示でき、メッセージの長さは言語によってかなり異なります。このため、いくつかの複数行メッセージに対して、いくつかの不幸なデフォルトのワード ラッピングになってしまいました。たとえば、日本語の翻訳では、1 行のテキスト全体が次の行に 1 ~ 2 文字だけ続くという結果になる場合がいくつかありました。
この問題を解決する Layout Utility クラスに次の 2 つのメソッドを追加しました (以下のコードを参照)。このソリューションは、任意の数の行 (1、2、3 など...) および任意の言語のラベルで機能します。ECLayoutUtility
(独自のクラス名に変更してください。)
基本的な考え方は次のとおりです。
テキストを表示する UILabel を指定して、現在の高さを検出します。
その高さを増やさないラベルの最小幅をバイナリ検索します。
以下の私のコードでは、変数while
を使用してループの精度とターン数の間のトレードオフを制御できます。granularity
この修正前の問題のある日本語ラベルの例:
修正後の同じ日本語ラベル:
これらは、Layout Utility クラスに追加した 2 つのメソッドです。私はそれらをこのように分割したので、たとえば Autolayout を使用していて、ラベル自体のサイズを直接変更するのではなく、サイズ情報を使用して制約を操作したい場合は、問い合わせて新しいサイズを取得することもできます。
+ (void)wordWrapEvenlyTextInUILabel:(UILabel *)uiLabel
forMaxWidth:(CGFloat)maxLabelWidth
{
[ECLayoutUtility resizeView:uiLabel
toSize:[self getLabelSizeWithMinimumWidthForLabel:uiLabel
forMaxWidth:maxLabelWidth]];
}
+ (CGSize)getLabelSizeWithMinimumWidthForLabel:(UILabel *)uiLabel
forMaxWidth:(CGFloat)maxLabelWidth
{
NSLog(@"Current size for label \"%@\" is %@", uiLabel.text, NSStringFromCGSize(uiLabel.frame.size));
// Start off by determining what height the label would get for the given maximum width:
CGSize labelSize = [uiLabel.text boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName:uiLabel.font }
context:nil].size;
// Constraining the label to that height, now figure out the mimumum width for
// which this label still shows its text within that given height. We find
// that height with a binary search for the smallest label width that does
// not increment the label height.
CGFloat maxWidth = maxLabelWidth;
CGFloat testWidth = 0.5 * maxWidth;
CGFloat minWidth = 0;
CGFloat granularity = 1;
while (maxWidth > testWidth + granularity)
{
CGFloat newHeight = [uiLabel.text boundingRectWithSize:CGSizeMake(testWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName:uiLabel.font }
context:nil].size.height;
NSLog(@"H: %.2f, min W: %.2f, mid W: %.2f, max W: %.2f", newHeight, minWidth, testWidth, maxWidth);
if (newHeight > labelSize.height)
{
// Width reduction lead to height increase, so new width is too small.
// Now set the new width to mid-point between what we just tried and
// the last known acceptable width:
minWidth = testWidth; // increase the lower bound
testWidth += 0.5 * (maxWidth - testWidth); // increase width for next test
}
else
{
// Height not affected by the width reduction, so lets try to reduce it even more:
maxWidth = testWidth; // reduce the upper bound
testWidth -= 0.5 * (testWidth - minWidth); // reduce width for next test
}
}
CGSize newSize = CGSizeMake(maxWidth, labelSize.height);
NSLog(@"New size for label \"%@\" is %@", uiLabel.text, NSStringFromCGSize(newSize));
return newSize;
}
次のように、View Controller+wordWrapEvenlyTextInUILabel:forMaxWidth:
からメソッドを呼び出しています。-viewWillLayoutSubviews
// Make sure that any text in the promo message that is wrapped over multiple lines
// is wrapped evenly, so we don't get very uneven lines that look ugly:
[ECLayoutUtility wordWrapEvenlyTextInUILabel:_promoMessageLabel
forMaxWidth:_promoMessageLabel.frame.size.width];
さまざまな言語のさまざまなラベルでこれをテストしましたが、完全に機能しているようです。以下はベトナム語の例です。
これが他の誰かにも役立つことを願っています:-)
ありがとう、
エリック