Как я могу центрировать NSAttributedString независимо от атрибутов?

#cocoa #text #drawing

#cocoa #текст #рисование

Вопрос:

Я хочу нарисовать NSAttributedString пользовательский вид и центрировать его по вертикали, Независимо от шрифта, размера и т.д. Строка представляет собой всего лишь небольшое число между 1-99.

До сих пор я пытался вызвать [NSAttributedString size] метод, позволяющий мне определять высоту строки в том виде, в каком она нарисована. План состоял в том, чтобы затем использовать показатель высоты для центрирования строки при ее рисовании с помощью drawInRect: или drawAtPoint: . Проблема, с которой я сталкиваюсь, заключается в том, что высота, возвращаемая методом size, больше, чем отображаемые глифы. После небольшого экспериментирования, кажется, size: метод возвращает высоту максимально высоких возможных символов с этими атрибутами, включая спускаемые элементы и т.д., А не высоту конкретных символов в моей NSAttributedString.

Обновить:

Как упоминалось Джошуа Ноцци в его ответе, я могу оценить, что максимальная высота — это то, что вы хотели бы использовать для вертикального центрирования, поскольку это предотвратило бы скачки вашего текста по вертикали при изменении строки. Однако в моем случае я хочу визуально центрировать число, например «10», часто внутри круга. При этом меня волнует фактическая высота строки «10».

Как бы я получил ограничивающую рамку, которая тесно связана с фактическими нарисованными символами? Я думаю, что я мог бы чего-то добиться, используя основной текст и CTLineGetImageBounds() функцию; однако, это много кода. Если бы я мог сделать это без использования такого подробного / низкоуровневого кода, это было бы лучше.

Я знаю, что, возможно, я полностью искажаю неправильное дерево с помощью вышеуказанного метода. Какой метод вы бы предложили? Нужно ли мне напрямую использовать Cocoa Text / основной текст, а не использовать дополнения к NSAttributedString?

Текстовая система в Mac OS настолько многофункциональна, что немного пугает новичка, такого как я. Любая помощь приветствуется.

Комментарии:

1. А, это хорошая деталь в вашем обновлении. Я обновил свой ответ.

Ответ №1:

Во-первых, вам определенно нужно поведение высоты, которое вы описали. Представьте, изменится ли нарисованная строка с использования символов, которым не нужна эта «дополнительная» высота, на использование символов, которым нужна. Нарисованная строка будет перемещаться по вертикали. нехорошо. Обязательно используйте высоту, заданную текстовой системой для указанного шрифта.

Чтобы ответить на ваш главный вопрос, drawInRect: перенесет ширину предоставленного прямоугольника в зависимости от атрибутов абзаца. Если вы вообще не хотите беспокоиться о переносе, лучше всего использовать -drawAtPoint: и вычислить центр вручную. Вертикальный центр равен половине высоты предлагаемого прямоугольника, в котором вы центрируете минус половина высоты размера приписываемой строки (или обычной строки sizeWithAttributes:). Координата y NSPoint, которую вы предоставляете -drawAtPoint: может быть вычислена с помощью NSMidY(rect) - ([attrString size].height / 2) .

Если вас действительно волнует перенос и вы уже знаете доступную ширину, вы можете использовать NSAttributedString -boundingRectWithSize:параметры:. Размер, который вы передаете, должен иметь ширину, равную вашей доступной ширине, а высоту, равную нулю. Это сообщает методу, который вы хотите узнать, необходимую высоту при переносе в заданную ширину. Затем вы можете использовать возвращенный прямоугольник в качестве прямоугольника для рисования для -drawInRect: а затем центрировать этот прямоугольник внутри любого целевого прямоугольника.

Я надеюсь, что это понятно и полезно. В вашем вопросе недостаточно деталей, чтобы быть более конкретным (т. Е., на что вы центрируете, разрешаете ли перенос, знаете ширину, но не высоту и т.д.).

Ничего из вышеперечисленного

Основываясь на вашем комментарии и обновлении, я думаю, вы можете использовать -[NSBezierPath appendBezierPathWithGlyph:inFont], чтобы получить путь к отдельному глифу, затем -[NSBezierPath bounds].size, чтобы получить его размер для центрирования. Это должно дать вам только то, что на самом деле извлекается из отдельного глифа.

Комментарии:

1. Спасибо Джошуа. Проблема в том, что если я использую максимальную высоту для глифа, а не высоту для моих конкретных символов, то то, что я рисую, может выглядеть немного странно, поскольку текст не будет центрирован по вертикали, как видно. В качестве примера, в некоторых случаях я действительно хочу нарисовать один глиф (символ из 1-5), визуально центрированный внутри круга. В этом случае я (думаю), что мне действительно нужна высота моих конкретных символов, а не высота самого высокого символа в этом размере шрифта / точки. Я слышу вашу точку зрения о том, что текст перемещается по вертикали, но это, вероятно, не имеет отношения к моему случаю.

2. Ах. Это та деталь, которую лучше всего опубликовать в вашем первоначальном вопросе. 🙂 Обновил мой ответ.

3. Извини, Джошуа, мой вопрос мог бы быть лучше. Я немного новичок, поэтому иногда не очевидно, что важно. Спасибо за совет. Похоже, что это сработает, если я буду рисовать число от 0 до 9, поскольку это один глиф. Было бы хорошо, если бы я мог найти обобщенное решение и для строк символов, поскольку в некоторых случаях я захочу рисовать числа выше 9.

4. Это тот момент, когда вы тратите некоторое время на чтение ссылки на API. Сразу после упомянутого мной метода NSBezierPath находится -appendBezierPathWithGlyphs:count:inFont: , который дает вам путь к нескольким символам. В остальном подход тот же.

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