正確なフレームとフォントを持つ 4 行の UILabel があります。
この文字列がラベルに適合するかどうか、および適合する最後の文字のインデックスは何かを知る必要があります。
正確なフレームとフォントを持つ 4 行の UILabel があります。
この文字列がラベルに適合するかどうか、および適合する最後の文字のインデックスは何かを知る必要があります。
答えの核心はCupcakeの参照投稿にあります。とにかく、sizeWithFont:constrainedToSize:lineBreakMode:
特定のワードラッピングが与えられた場合、特定の幅のラベルの特定のフォントでフレームのサイズがどのようになるかを把握するために使用できます。
CGSize size = [string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:UILineBreakModeWordWrap];
sizeConstraint
ラベルと同じ幅に設定しますが、高さを大きく設定します。結果size.height
が UILabel よりも大きい場合は、文字列が長すぎます。理論的には、最後の文字/単語を削除して再試行し、収まるまで繰り返すことができます。
文字列が非常に長いと思われる場合は、逆に、文字列の短い部分から始めて、文字列が大きくなりすぎるまで文字を追加し続けると、最後の文字がわかります。
いずれにせよ、このサイズの反復計算はかなり CPU を集中的に使用する操作になる可能性があるため、注意してください。
アップデート:
NSString
これは、デフォルトのフォントを使用して問題の文字列に収まる長さを返すアルゴリズムUILabel
です (ただし、最小フォント サイズは無視されます)。
- (NSUInteger)fitString:(NSString *)string intoLabel:(UILabel *)label
{
UIFont *font = label.font;
UILineBreakMode mode = label.lineBreakMode;
CGFloat labelWidth = label.frame.size.width;
CGFloat labelHeight = label.frame.size.height;
CGSize sizeConstraint = CGSizeMake(labelWidth, CGFLOAT_MAX);
if ([string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight)
{
NSString *adjustedString;
for (NSUInteger i = 1; i < [string length]; i++)
{
adjustedString = [string substringToIndex:i];
if ([adjustedString sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight)
return i - 1;
}
}
return [string length];
}
たとえば、単語区切りモードかどうかを確認し、次の単語区切りにジャンプしてから を呼び出すとsizeWithFont
、おそらくこれをより効率的にすることができますが、小さなUILabel
s の場合はこれで十分かもしれません。ワードラップ ロジックを利用して を呼び出す回数を最小限に抑えたい場合はsizeWithFont
、次のようになります。
- (NSUInteger)fitString:(NSString *)string intoLabel:(UILabel *)label
{
UIFont *font = label.font;
UILineBreakMode mode = label.lineBreakMode;
CGFloat labelWidth = label.frame.size.width;
CGFloat labelHeight = label.frame.size.height;
CGSize sizeConstraint = CGSizeMake(labelWidth, CGFLOAT_MAX);
if ([string sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height > labelHeight)
{
NSUInteger index = 0;
NSUInteger prev;
NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
do
{
prev = index;
if (mode == UILineBreakModeCharacterWrap)
index++;
else
index = [string rangeOfCharacterFromSet:characterSet options:0 range:NSMakeRange(index + 1, [string length] - index - 1)].location;
}
while (index != NSNotFound && index < [string length] && [[string substringToIndex:index] sizeWithFont:font constrainedToSize:sizeConstraint lineBreakMode:mode].height <= labelHeight);
return prev;
}
return [string length];
}
おそらく、ここで使用されている文字セットは正しくない可能性があります (たとえば、ハイフンを含める必要があります) が、その必要がなければ、文字ごとに行うよりもおそらくかなり近く、はるかに効率的です。