Цвет фона и закругленные углы NSAttributedString

У меня есть вопрос относительно закругленных углов и цвета фона текста для пользовательского UIView.

В принципе, мне нужно добиться такого эффекта (изображение прилагается - обратите внимание на закругленные углы с одной стороны) в пользовательском UIView: Background highlight

Я думаю, что подход к использованию:

  • Используйте основной текст для запуска глифов.
  • Проверить диапазон подсветки.
  • Если текущий пробег находится в пределах диапазона выделения, нарисуйте прямоугольник фона с закругленными углами и нужный цвет заливки перед тем, как рисовать глиф.
  • Нарисуйте глиф-прогон.

Однако я не уверен, является ли это единственным решением (или, если на то пошло, является ли это наиболее эффективным решением).

Использование UIWebView не является опцией, поэтому я должен сделать это в пользовательском UIView.

Мой вопрос: это лучший подход к использованию, и я на правильном пути? Или я упускаю что-то важное или иду по нему не так?

Ответ 1

Мне удалось достичь вышеупомянутого эффекта, поэтому подумал, что я отправлю ответ за то же самое.

Если у кого-то есть предложения по повышению эффективности, пожалуйста, не стесняйтесь. Я обязательно буду отмечать ваш ответ как правильный.:)

Для этого вам нужно добавить "настраиваемый атрибут" на NSAttributedString.

В принципе, это означает, что вы можете добавить любую пару "ключ-значение", если это то, что вы можете добавить к экземпляру NSDictionary. Если система не распознает этот атрибут, он ничего не делает. Для вас, как разработчика, вы можете предоставить настраиваемую реализацию и поведение для этого атрибута.

В целях этого ответа предположим, что я добавил пользовательский атрибут: @"MyRoundedBackgroundColor" со значением [UIColor greenColor].

В следующих шагах вам нужно будет понять, как CoreText получает материал. Ознакомьтесь с Руководством по программированию ядра Apple Core для понимания того, что работает/глиф/маркер/символ и т.д.

Итак, вот шаги:

  • Создайте пользовательский подкласс UIView.
  • У вас есть свойство для принятия NSAttributedString.
  • Создайте CTFramesetter с помощью этого экземпляра NSAttributedString.
  • Переопределить метод drawRect:
  • Создайте экземпляр CTFrame из CTFramesetter.
    • Вам нужно указать CGPathRef, чтобы создать CTFrame. Сделайте, чтобы CGPath был таким же, как кадр, в который вы хотите нарисовать текст.
  • Получить текущий графический контекст и перевернуть текстовую систему координат.
  • Используя CTFrameGetLines(...), получите все строки в CTFrame, которые вы только что создали.
  • Используя CTFrameGetLineOrigins(...), получите все исходные строки для CTFrame.
  • Запустите a for loop - для каждой строки в массиве CTLine...
  • Установите текстовую позицию в начало CTLine с помощью CGContextSetTextPosition(...).
  • Используя CTLineGetGlyphRuns(...), выполните все действия Glyph (CTRunRef) из CTLine.
  • Запустите еще один for loop - для каждого glyphRun в массиве CTRun...
  • Получить диапазон выполнения с помощью CTRunGetStringRange(...).
  • Получить типографские границы с помощью CTRunGetTypographicBounds(...).
  • Получить смещение x для выполнения с помощью CTLineGetOffsetForStringIndex(...).
  • Вычислить ограничивающий прямоугольник (назовем его runBounds), используя значения, возвращаемые из вышеупомянутых функций.
    • Помните - CTRunGetTypographicBounds(...) требует указателей на переменные для хранения "восхождения" и "спуска" текста. Вам нужно добавить их, чтобы получить высоту выполнения.
  • Получить атрибуты для запуска с помощью CTRunGetAttributes(...).
  • Проверьте, содержит ли словарь атрибута ваш атрибут.
  • Если ваш атрибут существует, вычислите границы прямоугольника, который должен быть окрашен.
  • Основной текст имеет начало строки на базовой линии. Нам нужно извлечь из нижней точки текста верхнюю точку. Таким образом, нам нужно настроить для снижения.
  • Итак, вычтите спуск из ограничивающего прямоугольника, который мы вычислили на этапе 16 (runBounds).
  • Теперь, когда у нас есть runBounds, мы знаем, в какой области мы хотим рисовать - теперь мы можем использовать любой из методов CoreGraphis/UIBezierPath для рисования и заполнения прямоугольника с помощью определенных закругленных углов.
    • UIBezierPath имеет метод класса удобства, называемый bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:, который позволяет вам обходить определенные углы. Вы указываете углы с использованием бит-масок во втором параметре.
  • Теперь, когда вы заполнили прямоугольник, просто нарисуйте глиф-прогон с помощью CTRunDraw(...).
  • Празднуйте победу за то, что создали свой собственный атрибут - пить пиво или что-то в этом роде!: D

Относительно обнаружения того, что диапазон атрибутов распространяется на несколько прогонов, вы можете получить весь эффективный диапазон вашего настраиваемого атрибута, когда первый запуск встречает этот атрибут. Если вы обнаружите, что длина максимального эффективного диапазона вашего атрибута больше, чем длина вашего прогона, вам нужно нарисовать острые углы с правой стороны (слева направо script). Более математика позволит вам определить стиль подсветки для следующей строки.:)

Прилагается скриншот эффекта. Ящик сверху - это стандартный UITextView, для которого я установил атрибутText. Ящик внизу - тот, который был реализован с использованием вышеуказанных шагов. Такая же атрибутная строка была установлена ​​как для текстовых. custom attribute with rounded corners

Опять же, если есть лучший подход, чем тот, который я использовал, пожалуйста, дайте мне знать!: D

Надеюсь, это поможет сообществу.:)

Ура!