NSString boundingRectWithSize немного занижает правильную высоту - почему?

Я пытаюсь автоматически изменить размер текстового поля / представления в зависимости от его текущей ширины. Другими словами, я хочу, чтобы ширина оставалась постоянной, но меняла высоту в соответствии с предоставленным ей текстом.

Кажется, он работает, но по какой-то причине выравнивается по нижней части моего окна, несмотря на попытки вручную переместить его обратно. Кто-нибудь может понять, что я здесь делаю не так?

введите описание изображения здесь

NSString *temp = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est, facilisis a feugiat in, consectetur eget arcu. Aenean rutrum, lacus id euismod congue, nisl erat vulputate lectus, non faucibus tortor purus sed sem. Donec tempor dui egestas velit auctor vitae faucibus diam facilisis. Morbi convallis nulla quis est pulvinar quis ultricies sem sollicitudin.";

myText.stringValue = temp;

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                            [NSFont systemFontOfSize:12], NSFontAttributeName,
                            [NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName,
                            nil];

NSSize size = NSMakeSize(window.frame.size.width, 200);
myText.frame = [temp boundingRectWithSize:size options:NSLineBreakByWordWrapping | NSStringDrawingUsesLineFragmentOrigin attributes:attributes];

РЕДАКТИРОВАТЬ: даже при ручном перемещении рамки видно, что текст все равно обрезается. Недавно скорректированный размер не совсем там. введите описание изображения здесь

это относится к: NSString boundingRectWithSize слегка занижает правильную ширину - почему? и NSTextView или NSTextField автоматически изменяют размер границ / фрейма?


person Desh__    schedule 23.08.2012    source источник
comment
Возможно, измените высоту с 200 на что-то намного большее, чтобы размер кадра увеличивался по вертикали.   -  person rein    schedule 23.08.2012
comment
@rein Я продолжаю играть с этим, и хотя он действительно меняет размер нового фрейма, он все еще обрезает текст внизу. Новая рама недостаточно велика. См. Обновленный вопрос для нового снимка экрана.   -  person Desh__    schedule 23.08.2012


Ответы (4)


У меня такая же проблема. В документации я нашел следующее:

Чтобы правильно рисовать и изменять размер многострочного текста, передайте NSStringDrawingUsesLineFragmentOrigin в параметре options.

Этот метод возвращает дробные размеры (в компоненте размера возвращаемого CGRect); чтобы использовать возвращаемый размер для размеров представлений, вы должны поднять его значение до ближайшего большего целого числа с помощью функции ceil.

Итак, это решило это для меня:

CGRect rect = [myLabel.text boundingRectWithSize:CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)
                                                            options:NSStringDrawingUsesLineFragmentOrigin
                                                            attributes:@{NSFontAttributeName: myLabel.font}
                                                            context:nil];
rect.size.width = ceil(rect.size.width);
rect.size.height = ceil(rect.size.height);

Обновление (Swift 5.1)

Альтернативный способ сделать это в Swift:

let size = myLabel.text!.size(
    withAttributes: [.font: myLabel.font!]
)
let rect = CGSize(
  width: ceil(size.width),
  height: ceil(size.height)
)

См. этот ответ для примера Objective-C.

person r-dent    schedule 09.05.2014
comment
Спасибо за это, мне очень помогли - person phyzalis; 09.06.2014
comment
ИЛИ с NSLineBreakByWordWrapping недействительно и в любом случае не работает для меня. Это не член перечисления NSStringDrawingOptions. - person iphone007; 22.11.2014
comment
Хм .. Вы правы! Вы пробовали это только с NSStringDrawingUsesLineFragmentOrigin? Это сработало? Тогда я бы отредактировал фрагмент. - person r-dent; 23.11.2014
comment
Размер обычно рассчитывается, когда вам нужно добавить предмет под этикеткой. Итак, рассчитайте размер и добавьте элемент под меткой в ​​соответствии с рассчитанной высотой, для настройки метки выполните [myLabel sizeToFit]; - person AsifHabib; 12.12.2014
comment
Спасибо! Универсальный ответ для меня - RTFM :) - person surfrider; 12.02.2015
comment
В руководстве сказано, что результат нужно поднять до «ближайшего большего целого числа». Я предполагаю, что они имели в виду ceil (h + 1), потому что именно так я заставил его работать. А если серьезно, почему это исправление не внесено в API? Черт возьми, яблоко ... - person Jonathan Zrake; 09.02.2019

Это немного окольный путь, но я обнаружил, что запрос NSTextFieldCell дает гораздо более точные / надежные результаты по высоте, чем использование [NSAttributedString boundingRectWithSize:options:].

Предполагая, что интересующая строка уже находится в NSTextField с соответствующими установленными параметрами форматирования / упаковки, затем запросите текстовую ячейку, какой размер, по ее мнению, должен соответствовать указанной ширине:

NSTextField* textField = ...

NSSize cellSize = [textField.cell cellSizeForBounds:NSMakeRect(0, 0, pathText.frame.size.width, CGFLOAT_MAX)];

cellSize.height дает высоту, которую текст фактически использует при рисовании.

person user2067021    schedule 07.11.2012

Это то, к чему я пришел (по крайней мере, на данный момент), похоже, он работает нормально, однако я все еще чувствую, что есть лучший способ добиться этого.

NSString *temp = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel felis nec massa ultricies blandit non id arcu. Sed enim est.";

myText.stringValue = temp;

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                            [NSFont systemFontOfSize:12], NSFontAttributeName,
                            [NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName,
                            nil];

NSSize size = NSMakeSize(window.frame.size.width, MAXFLOAT);


myText.frame = [temp boundingRectWithSize:size options:NSLineBreakByWordWrapping | NSStringDrawingUsesLineFragmentOrigin attributes:attributes];

// Keep current width but add some more on the bottom
NSSize tF = myText.frame.size;
[myText setFrameSize:NSMakeSize(tF.width, tF.height + 35)];

[myText setFrameOrigin:NSMakePoint((NSWidth(window.frame) - NSWidth(myText.frame)) / 2, 
                                   (NSHeight(window.frame) -  NSHeight(myText.frame) - 20))];

[myText setAutoresizingMask:NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin];

Производит это:

введите описание изображения здесь

person Desh__    schedule 23.08.2012

Я обнаружил, что NSString # boundingRectWithSize никогда не бывает абсолютно правильным, единственное, что, кажется, работает хорошо, - это то, что описано здесь: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html

class func sizeForString(_ text : String, withFont font: NSFont, inWidth maxWidth: CGFloat) -> NSSize {
    let textStorage = NSTextStorage(string: text)
    let textContainer = NSTextContainer(containerSize: NSSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude))
    let layoutManager = NSLayoutManager()
    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)
    textStorage.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, textStorage.length))
textContainer.lineFragmentPadding = 0
    layoutManager.glyphRange(for: textContainer)
    return layoutManager.usedRect(for: textContainer).size
 }
person valR    schedule 10.08.2017