2010-02-17 1 views
43

Я хочу сделать некоторые чертежи NSAttributedStrings в коробках с фиксированной шириной, но у меня возникли проблемы с вычислением правильной высоты, которую они будут занимать при рисовании. До сих пор я пытался:Как получить высоту для NSAttributedString с фиксированной шириной

  1. Вызов - (NSSize) size, но результаты бесполезны (для этой цели), так как они дают то, что ширина строковых желания.

  2. Вызов - (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options с прямоугольной формой в ширину и NSStringDrawingUsesLineFragmentOrigin в настройках, точно так же, как я использую в своем чертеже. Результаты ... трудно понять; конечно, не то, что я ищу. (Как указано в ряде мест, в том числе this Какао-Dev-нить).

  3. Создание временного NSTextView и делает:
    [[tmpView textStorage] setAttributedString:aString];
    [tmpView setHorizontallyResizable:NO];
    [tmpView sizeToFit];

    Когда я запрашиваю кадр tmpView, ширина остается по желанию, а высота часто правильно ... пока не дойдете до длинных строк, когда это часто половину от размера, который требуется. (Кажется, что максимальный размер не попал: один кадр будет 273.0 (около 300 слишком короткий), другой будет 478.0 (только 60-ий слишком короткий)).

Буду признателен за любые указатели, если кому-либо это удалось.

ответ

15

Ответ является использовать
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
Но rect вы передаете должны иметь 0.0 в измерении вы хотите быть неограничен (который, гм, имеет смысл). Пример here.

+2

Этот ответ устарел. [Ответ Грэма] (http://stackoverflow.com/a/2460091/39155) ниже - правильный метод по состоянию на 2014 год. –

6

Возможно, вас заинтересует отличная (только OS X) модель Джерри Крайнока (OS X), которая предназначена для выполнения всех видов измерения струн, включая то, что вы ищете.

+1

Этот код является специфичным для Mac. Это не поможет в разработке iOS. – Brennan

+3

Вы правы, вопрос был о 'NSTextView', который является классом Mac. Я даже не уверен, что у iOS была «NSAttributedString», когда я ответил на этот вопрос. –

+1

Поздний ввод, но только хэдз-ап: у меня были проблемы с NS (Attributed) Строка + Геометрия, последовательно недооценивающая высоту, требуемую длинными строками. До сих пор я на самом деле просто подтолкнул результат, добавив дополнительные 25%. Теперь я ищу новое, лучшее решение. Я не думаю, что NS (Attributed) String + Geometrics работает хорошо на 10.9, 10.10 и 10.11. – Bryan

31
-[NSAttributedString boundingRectWithSize:options:] 

Вы можете указать NSStringDrawingUsesDeviceMetrics получить union of all glyph bounds.

В отличие от -[NSAttributedString size], возвращаемый NSRect представляет размеры области, которая изменится, если строка будет нарисована.

Как @Bryan комментарии, boundingRectWithSize:options: устарел (не рекомендуется) в OS X 10.11 и более поздних версиях. Это связано с тем, что стиль стилей теперь динамический в зависимости от контекста.

Для OS X 10.11 и более поздних версий см. Документацию разработчика Apple Calculating Text Height.

+0

Кажется, что если вы используете 'NSStringDrawingUsesDeviceMetrics' и нет глифов, это вернет' 0'. Есть ли способ справиться с обеими ситуациями? Или вам нужно знать, как вы знаете или отслеживаете, добавили ли вы глиф? (Протестировано на iOS 8.) – zekel

+0

Имеет смысл, что строка без видимого содержимого вернет нулевой размер прямоугольника. Вы видите новое поведение на iOS 8 по сравнению с iOS 7? –

+0

Я имел в виду, что если у вас есть 'NSAttributedString' с текстом (и без глифов), и вы используете' NSStringDrawingUsesDeviceMetrics', то размер 'CGSizeZero'. Так что вам кажется, что вам нужно знать, есть ли глифы, прежде чем вы решите, как получить размер ... – zekel

2

Применение NSAttributedString метод

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context 

Размер является ограничение на площади, расчетная ширина площадь ограничена указанной ширины, тогда как высота гибкой основе этой ширины. Можно указать nil для контекста, если это невозможно. Чтобы получить многострочный размер текста, используйте NSStringDrawingUsesLineFragmentOrigin для параметров.

1

Я просто потратил кучу времени на это, поэтому я предоставляю дополнительный ответ, чтобы спасти других в будущем.Ответ Грэма 90% правильно, но он отсутствует один ключевой фрагмент:

Чтобы получить точные результаты с -boundingRectWithSize:options:вы должны пройти следующие параметры:

NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesDeviceMetrics|NSStringDrawingUsesFontLeading` 

Если опустить lineFragmentOrigin один, вы будете получить глупость назад; возвращенный прямоугольник будет одной строкой высокой и совсем не будет уважать размер, который вы передаете в метод.

Почему это так сложно и так плохо документировано вне меня. Но у вас это есть. Передайте эти варианты, и он будет работать отлично (по крайней мере на OS X).

+0

Кроме того: предполагается, что у вас есть NSAttributedString, созданный с заданным шрифтом и NSParagraphStyle, который вы ищете, - в моем случае это стиль с абзацем с выравниванием по словам, без слов. Не забудьте создать это, когда вы создадите свой атрибутString. – Bryan

+0

Этот метод устарел 10.11+ и больше не работает правильно; возвращенная высота слишком мала на El Capitan. – Bryan

1

На OS X 10.11+ следующий метод работает для меня (от Calculating Text Height документа от Apple)

- (CGFloat)heightForString:(NSAttributedString *)myString atWidth:(float)myWidth 
{ 
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:myString]; 
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: 
     NSMakeSize(myWidth, FLT_MAX)]; 
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 
    [layoutManager addTextContainer:textContainer]; 
    [textStorage addLayoutManager:layoutManager]; 
    [layoutManager glyphRangeForTextContainer:textContainer]; 
    return [layoutManager 
     usedRectForTextContainer:textContainer].size.height; 
} 
0

Ни одного ответа на этой странице, работал для меня, и сделал это древний старый код Objective-C от Apple's documentation. То, что я наконец-таки получить работу для UITextView сначала установив его text или attributedText собственности на него, а затем расчета необходимого размера, как это:

let size = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.max)) 

отлично работает. Booyah!

1

Swift 3:

let attributedStringToMeasure = NSAttributedString(string: textView.text, attributes: [ 
     NSFontAttributeName: UIFont(name: "GothamPro-Light", size: 15)!, 
     NSForegroundColorAttributeName: ClickUpConstants.defaultBlackColor 
]) 

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: widthOfActualTextView, height: 10)) 
placeholderTextView.attributedText = attributedStringToMeasure 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 

Этот ответ отлично работает для меня, в отличие от остальных, которые дали мне неправильные высоты для больших строк.

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

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: ClickUpConstants.screenWidth - 30.0, height: 10)) 
placeholderTextView.text = "Some text" 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 
0

Как много парней, упомянутых выше, и основания на моем тесте.

Я использую open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRect на прошивке, как эти ниже:

let rect = attributedTitle.boundingRect(with: CGSize(width:200, height:0), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) 

Здесь 200 является фиксированной шириной, как ожидаемый, высоты Ставит 0, так как я считаю, что лучше, чтобы отчасти сказать высоту API is неограниченный.

Вариант здесь не так важен, я попробовал .usesLineFragmentOrigin или .usesLineFragmentOrigin.union(.usesFontLeading) или .usesLineFragmentOrigin.union(.usesFontLeading).union(.usesDeviceMetrics), он дает тот же результат.

И результат ожидается как мой.

Спасибо.

2

У меня есть сложная строка с несколькими шрифтами и получен неправильный результат с несколькими из вышеперечисленных ответов, которые я пробовал в первую очередь. Использование UITextView дало мне правильную высоту, но было слишком медленным для моего варианта использования (ячейки для выбора размера). Я написал быстрый код, используя тот же общий подход, описанный в ранее упомянутом Apple doc и описанном Эриком. Это дало мне правильные результаты с более быстрым выполнением, чем при использовании UITextView.

private func heightForString(_ str : NSAttributedString, width : CGFloat) -> CGFloat { 
    let ts = NSTextStorage(attributedString: str) 

    let size = CGSize(width:width, height:CGFloat.greatestFiniteMagnitude) 

    let tc = NSTextContainer(size: size) 
    tc.lineFragmentPadding = 0.0 

    let lm = NSLayoutManager() 
    lm.addTextContainer(tc) 

    ts.addLayoutManager(lm) 
    lm.glyphRange(forBoundingRect: CGRect(origin:CGPoint(x:0,y:0),size:size), in: tc) 

    let rect = lm.usedRect(for: tc) 
    return rect.size.height 
} 
+0

работал как шарм – Harish

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