web-dev-qa-db-ja.com

NSString boundingRectWithSizeが不必要に高い高さを返す

[NSString boundingRectWithSize:options:attributes]を使用すると、返される四角形のサイズが、特定の文字列で予想されるサイズよりも高くなります。返される高さは、文字列自体の高さではなく、指定された属性を持つ文字列の可能な最大の高さを表すように見えます。

同じ属性とオプションを想定すると、文字列 "cars"に対して返される高さは、文字列 "ÉTAS-UNIS"に対して返される高さと同じです(Eのアクセントに注意してください)。

私はboundingRectWithSizeが指定された文字列の文字のみを考慮することを期待していましたが、私の意見では、文字列 "cars"の高さは短くなります。

添付のスクリーンショットでは、boundingRectWithSizeから返された四角形を塗りつぶし、境界の四角形が本来あるべきであると想定していたものを赤で示しています。長方形の幅は私が予想するようにかなりですが、高さは私が予想したよりもかなり高いです。何故ですか?

Bounding Rect Example

サンプルコード:

NSRect boundingRect = NSZeroRect;
NSSize constraintSize = NSMakeSize(CGFLOAT_MAX, 0);

NSString *lowercaseString = @"cars";
NSString *uppercaseString = @"ÉTAS-UNIS";
NSString *capitalizedString = @"Japan";

NSFont *drawingFont = [NSFont fontWithName:@"Georgia" size:24.0];
NSDictionary *attributes = @{NSFontAttributeName : drawingFont, NSForegroundColorAttributeName : [NSColor blackColor]};

boundingRect = [lowercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Lowercase rect: %@", NSStringFromRect(boundingRect));

boundingRect = [uppercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Uppercase rect: %@", NSStringFromRect(boundingRect));

boundingRect = [capitalizedString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Capitalized rect: %@", NSStringFromRect(boundingRect));

出力:

Lowercase rect: {{0, -6}, {43.1953125, 33}}
Uppercase rect: {{0, -6}, {128.44921875, 33}}
Capitalized rect: {{0, -6}, {64.5, 33}}
18
kennyc

オプションでNSStringDrawingUsesDeviceMetricsを使用することもできます。 docs から:

NSStringDrawingUsesDeviceMetrics

レイアウトを計算するときは、(活版印刷の境界ではなく)画像のグリフの境界を使用します。

27
omz

@omzは、私のためにこの作業を行ったことで今でも信用を得ています。 boundingRectWithSizeのようなものが最終的にCoreText関数を呼び出すと思うので、彼の答えは私にCoreTextをもう少し見回させました。

WWDC 2012のセッション226には、行のメトリックの計算に専念するセクション全体があり、驚いたことに、彼らはCTLineGetBoundsWithOptionsと呼ばれる新しいCoreText関数について話しました。

私の知る限り、そのメソッドはCTLine.hおよびCoreText Changes 資料。ドキュメントで通常の検索を行っても、(私にとっては)明らかになりません。

しかし、それは機能しているように見え、私のテストでは、システムにインストールされているすべてのフォントに対してboundingRectWithSizeとまったく同じ結果を返します。さらに良いのは、boundingRectWithSizeよりもほぼ2倍速いように見えることです。

WWDCビデオが言及しているように、行の高さなどを考慮せずに文字列の境界を計算する必要がある理由は少しあいまいですが、それを行う必要がある場合は、これが最良の方法だと思います使用する。いつものように、YMMV。

大まかなサンプルコード:

NSFont *font = [NSFont systemFontOfSize:13.0];
NSDictionary *attributes = @{(__bridge NSString *)kCTFontAttributeName : font};
NSAttributedString *attributeString = [[NSAttributedString alloc] initWithString:self.text attributes:attributes];

CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attributeString);
CGRect bounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsUseGlyphPathBounds);

CFRelease(line);

return NSRectFromCGRect(bounds);
5
kennyc

omzの答え に基づくSwift 3+ソリューション:

let string: NSString = "test"
let maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
let boundingRect = string.boundingRect(with: maxSize, options: .usesDeviceMetrics, attributes: <string attributes>)
0
Tamás Sengel

boundingRectWithSize関数を試しましたが、うまくいきませんでした。

うまくいったのはsizeThatFitsでした

使用法:

CGSize maxSize = CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)

CGSize size = [myLabel sizeThatFits:maxSize];
0
Shaked Sayag