2015-08-23 3 views
0

Для просмотра изображений в NSTableView Мне нужно рассчитать текст в NSTextField. Я использую этот метод:Рассчитать высоту текстового контейнера

float heightForStringDrawing(NSString *myString, NSFont *myFont,float myWidth) { 
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:myString]; 
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(myWidth, FLT_MAX)]; 
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 
    [layoutManager addTextContainer:textContainer]; 
    [textStorage addLayoutManager:layoutManager]; 
    [textStorage addAttribute:NSFontAttributeName value:myFont 
         range:NSMakeRange(0, [textStorage length])]; 


    (void) [layoutManager glyphRangeForTextContainer:textContainer]; 
    return [layoutManager usedRectForTextContainer:textContainer].size.height; 
} 

В случае линии лайнеры это работает хорошо, но когда у меня есть более чем одна линия для точной ширины моей высоты вид слишком мал. Я искал ответ часами, но у меня все еще ничего нет. Вот снимок экрана:

enter image description here

Я добавляю десять к результату функции из-за заполнения. Как вы можете видеть для короткого сообщения, он работает хорошо, дольше он обрезается. Спасибо за помощь.

ответ

1

Вы не указали код, который вызывает вашу функцию heightForStringDrawing(). Какую ширину вы предоставляете? Если это ширина текстового поля, это неправильно, потому что текст в текстовом поле не разрешается полностью переходить к краям текстового поля. Также есть горизонтальная прокладка.

В любом случае, есть более простой подход. Создайте текстовое поле, соответствующее свойствам той, которую вы пытаетесь измерить. Установите его stringValue и font. Установите его preferredMaxLayoutWidth на доступную ширину. (Обратите внимание, что это касается выравнивания rect, а не прямоугольника. Используйте -alignmentRectForFrame:, если вам нужно преобразовать.) Теперь спросите его о его intrinsicSize. Затем вам необходимо преобразовать это из выравнивания rect в frame rect, используя -frameForAlignmentRect:.

В зависимости от вашей ситуации вы можете дублировать существующее текстовое поле, архивируя и разгружая его, или вы можете загрузить NIB, который содержит его, чтобы получить его.


Один из способов получения текстового поля с необходимыми характеристиками, чтобы клонировать существующий:

NSData* data = [NSKeyedArchiver archivedDataWithRootObject:_label]; 
NSTextField* clone = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

Чтобы рассчитать необходимую высоту кадра, чтобы поместиться в заданной ширины:

NSRect rect = { NSZeroPoint, NSMakeSize(desiredWidth, 100 /* arbitrary */) }; 
rect = [clone alignmentRectForFrame:rect]; 
clone.preferredMaxLayoutWidth = NSWidth(rect); 
rect.size = clone.intrinsicContentSize; 
rect = [clone frameForAlignmentRect:rect]; 
CGFloat resultingHeight = NSHeight(rect); 

Теперь, в вашем скриншоте, высота строки должна быть выше высоты текстового поля, потому что там есть запас. Насколько высока зависимость от вашего макета. Поскольку вы упоминаете ограничения в своем комментарии, вы, вероятно, используете автоматическую компоновку. В этом случае поля (ограничения) будут фактически применены к выравниванию прямоугольника текстового поля. Итак, вы пропустили бы вторую в последнюю строку кода. То есть высота строки будет неотъемлемой высотой текстового поля (не скорректирована) плюс полями, налагаемыми вашими ограничениями.

Чтобы избежать большого количества этого материала при игре с полями, вы должны работать над полной иерархией представлений, соответствующей виду ячейки таблицы. Таким образом, вы напрямую загрузите представление таблицы NIB таблицы. Вы должны установить содержимое текстового поля, если это необходимо (и любое другое содержимое, которое требуется для просмотра в вашем представлении ячеек). Вы должны применить ограничение ширины к самому ядру ячейки, чтобы имитировать ширину столбца. Затем вы спросите вид ячейки для своего fittingSize. Пусть система автоматического компоновки вычисляет общую высоту, включая поля и все, что подразумевается под вашими ограничениями, из содержимого.

Конечно, это работает только в том случае, если текстовое поле использует preferredMaxLayoutWidth. В противном случае он не увеличит свою внутреннюю высоту в ответ на упаковку. Поскольку вы не хотите жестко кодировать предпочтительную ширину или размер полей, вы можете сделать два прохода.После установки содержимого элементов управления в виде ячеек и добавления ограничения ширины вызовите -layoutSubtreeIfNeeded. Затем запросите рамку текстового поля, преобразуйте ее в прямоугольник выравнивания, установите preferredMaxLayoutWidth в ширину выравнивания и только затем выполните запрос в виде ячейки fittingSize.

+0

'NSString * с = @ "слишком длинное строковое значение, чтобы положить его в комментарии";' 'NSFont * шрифт = [NSFont fontWithName: @ "Helvetica Neue" size: 13]; ' ' h = heightForStringDrawing (s, font, 100-4); ' Вот как я вызываю этот метод. 100 - ширина закругленного зеленого цвета. -4 из-за ограничений customView - текстовое поле (2 стороны). Я уже пробовал ваш подход, но он тоже не работает. Он возвращает еще более низкую высоту, чем требуется. – PawelPawel

+0

Я обновил свой ответ. Я забыл отметить, что вам нужно преобразовать внутреннюю высоту из выравнивания rect в прямоугольник. –

+0

@ Ąowski, я снова обновил свой ответ с примером кода. Я также описываю подход, использующий представление целой ячейки, поскольку он подвержен ошибкам воспроизводить ваши границы ограничений в коде. –

0

Прекрасно рабочий раствор для меня:

// creating temporary cell just to take height from it later 
NSTextFieldCell *tmp = [NSTextFieldCell new]; 
// settings proper values from out NSTextField which we want to check height for 
[tmp setStringValue:s]; 
[tmp setFont:font]; 
NSRect rect; 
rect.size.height=FLT_MAX; 
// width which we want to check height for 
// in my case 100 (width of nstextfield), -4 (minus left and right margin) 
rect.size.width=100-4; 
// getting needed height 
h = [tmp cellSizeForBounds:rect].height; 
+0

Это получает размер ячейки справа, но не размер текстового поля, который бы удерживал его. Он игнорирует некоторые поля вокруг границы, которые использует текстовое поле. –

+0

Как насчет того, чтобы вставить его в «NSTextField», а затем взять размер? Я попробовал то, что вы разместили выше, но либо он не работает, либо я не понимаю. – PawelPawel