Ответ 1
Возможно, вы захотите использовать NSStringDrawingUsesDeviceMetrics
в параметрах. Из docs:
NSStringDrawingUsesDeviceMetrics
Используйте границы глифов изображения (вместо типографских границ) при расчете макета.
При использовании [NSString boundingRectWithSize:options:attributes]
размер возвращаемого прямоугольника выше, чем я ожидал бы для определенных строк. Возвращаемая высота представляет собой максимально возможную высоту строки с указанными атрибутами, а не высоту самой строки.
Предполагая те же атрибуты и параметры, высота, возвращаемая для строки "cars
", равна той же высоте, что и для строки "ÉTAS-UNIS
" (обратите внимание на акцент на E).
Я бы ожидал, что boundingRectWithSize
рассмотрит только символы в данной строке, которые, на мой взгляд, вернут более короткую высоту для строки "cars
".
В прикрепленных скриншотах я заполнил прямоугольник, возвращенный из boundingRectWithSize
, и обозначил красным то, что я предположил бы, что ограничивающий прямоугольник должен был быть. Ширина прямоугольника в значительной степени, как я ожидал бы, но высота значительно выше, чем я ожидал. Почему это?
Пример кода:
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}}
Возможно, вы захотите использовать NSStringDrawingUsesDeviceMetrics
в параметрах. Из docs:
NSStringDrawingUsesDeviceMetrics
Используйте границы глифов изображения (вместо типографских границ) при расчете макета.
@omz все еще получает кредит за выполнение этой работы для меня. Его ответ заставил меня еще раз взглянуть на CoreText, так как я предполагаю, что что-то вроде boundingRectWithSize
в конечном итоге вызывает функцию CoreText.
В сеансе 226 от WWDC 2012 был целый раздел, посвященный вычислению метрик линии, и, к моему удивлению, они рассказали о новой функции CoreText под названием CTLineGetBoundsWithOptions
.
Насколько я могу судить, этот метод документируется только в CTLine.h
и в документе CoreText Changes
. Это, конечно, не возникает (для меня) при обычном поиске в документации.
Но, похоже, он работает, и в моем тестировании он возвращает тот же результат, что и boundingRectWithSize
для всех шрифтов, установленных в моей системе. Еще лучше, что он почти в 2 раза быстрее, чем boundingRectWithSize
.
Как упоминается в видео 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);
Я попробовал функцию boundingRectWithSize
, но для меня это не сработало.
Что работало sizeThatFits
Использование:
CGSize maxSize = CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)
CGSize size = [myLabel sizeThatFits:maxSize];
Быстрое решение 3+, основанное на ответе omz:
let string: NSString = "test"
let maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
let boundingRect = string.boundingRect(with: maxSize, options: .usesDeviceMetrics, attributes: <string attributes>)