2014-01-22 9 views
17

При использовании [NSString boundingRectWithSize:options:attributes] размер прямоугольника, который возвращается, выше, чем я ожидал бы для определенных строк. Возвращаемая высота представляет собой максимально возможную высоту строки с указанными атрибутами, а не высоту самой строки.NSString boundingRectWithSize, возвращающий излишне высокую высоту

Предполагая одинаковые атрибуты и параметры, высота, возвращаемая для строки «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}} 
+0

Пожалуйста, проверьте ответ на подобный вопрос здесь- [http://stackoverflow.com/a/27289303/591811][1] [1]: http://stackoverflow.com/a/27289303/591811 – shoan

ответ

25

Вы можете использовать NSStringDrawingUsesDeviceMetrics в настройках. Из docs:

NSStringDrawingUsesDeviceMetrics

Используйте изображение глифа границы (вместо типографских границ) при вычислении макета.

+0

я все, но уверен, что я пытался этот флаг, но я предполагаю, что я всегда пробовал рядом с 'флагом NSStringDrawingUsesLineFragmentOrigin', которые не дают результатов, которые я хотел. Используется один, это так. Спасибо. Кажется, удивительно сложно нарисовать идеальный размер за некоторым усеченным текстом. При запросе ограничительного прямоугольника с 'NSStringDrawingUsesLineFragmentOrigin' включает в себя« padding », но этот флаг появляется для« NSStringDrawingTruncatesLastVisibleLine », который будет использоваться. – kennyc

4

@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); 
+0

'CTLineGetBoundsWithOptions' также упоминается в документе« Что нового »для ОС 10.8. – JWWalker

+1

Благодарим вас за упоминание CTLineGetBoundsWithOptions возвращает правильный размер текста, а boundingRectWithSize: options: context: дает мне удвоенную высоту в iOS 8. Совершенно странно. Теперь пришло время выяснить, как обернуть текст. – Ben

+0

Я вижу, что iOS8 удваивает высоту вычисленного текста, независимо от параметров, которые я задал. CTLineGetBoundsWithOptions работает как шарм. – u2Fan

0

Я пробовал функцию boundingRectWithSize, но она не работает для меня.

Что работа sizeThatFits

Использование:

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

CGSize size = [myLabel sizeThatFits:maxSize]; 
+0

Вопрос отмечен как iOS, так и OSX, но я думаю, что 'sizeThatFits:' доступен только на iOS. – JWWalker

Смежные вопросы