Как сделать вертикальный текст UILabel и UITextView для iOS в Swift?

Если вы пришли к этому вопросу на основе названия, но не заинтересованы в монгольском, вы можете искать этот Q & A вместо:


Я изучаю Swift для разработки приложений iOS для традиционного монгольского. Проблема в том, что традиционный монгольский язык написан вертикально сверху донизу и слева направо. Мой вопрос заключается в том, как отображать текст по вертикали и все еще работать с оберткой строк?

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

enter image description here

Для простой однолинейной UILabel будет работать поворот на 90 градусов по часовой стрелке. Однако для многострочного UITextView мне нужно иметь дело с оберткой строк. Если я просто сделаю обычный поворот на 90 градусов, первое, что написано, окажется на последней строке.

До сих пор я сделал план, который, как я думаю, может решить эту проблему:

  • Создайте собственный шрифт, в котором все буквы зеркалируются вертикально.
  • Поворот текстового вида на 90 градусов по часовой стрелке.
  • Зеркальное отображение текста по горизонтали.

enter image description here

Это должно позаботиться об обертке текста.

Я могу сделать зеркальный шрифт. Тем не менее, я не знаю, как сделать Swift кодирование для вращения и зеркалирования UITextView. Я нашел следующие ссылки, которые, похоже, дают подсказки частям решения, но все они находятся в Objective C, а не в Swift.

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

Update

Ответ на

@sangonz по-прежнему остается отличным ответом, но я временно не обозначил его как принятый ответ, потому что я просто не мог заставить все работать. В частности:

  • Включение прокрутки (путем встраивания пользовательского представления в scrollview или под подклассом UIScrollView). В проекте github @sangonz сказал, что это должно быть легко, но это было не для меня.
  • Получение ретрансляции (а не растяжения) строк слова при изменении ориентации. Я думаю, что это не должно быть слишком сложно решить с небольшим количеством исследований.
  • Почему текстовые строки не пересекаются до края представления? В нижней части есть большая щель.
  • Как отключить NSTextStorage пользовательского вертикального представления от другого UITextView. (см. этот вопрос)

До этого момента Я использовал оригинальный метод, предложенный выше, но я действительно хочу получить что-то вроде того, что предложил @sangonz.

Я также рассматриваю альтернативные методы, такие как

Ответ 1

Изменить: Вот как я это сделал.

Вот очень простая реализация в моем GitHub: Vertical-Text-iOS.

Ничего особенного, но это работает. Наконец, мне пришлось смешивать TextKit и обработку изображений. Взгляните на код. Он включает в себя:

  • Подкласс NSTextContainer, чтобы получить правильные размеры текста.
  • Создание пользовательского UIView для визуализации текста, применяющего аффинные преобразования к каждой строке, и рендеринг с использованием NSLayoutManager для сохранения всех функций TextKit.

Способ TextKit

Правильный способ сохранить все преимущества родного текста (например, выделение, выделение...) - использовать стандартные API TextKit. Метод, который вы предлагаете, нарушит все это или может привести к странному поведению.

Однако, похоже, что TextKit в iOS еще не поддерживает вертикальную ориентацию, но он готов к этому. Как примечание, в OS X оно несколько поддерживается, и вы можете вызвать textView.setLayoutOrientation(.Vertical), но он все еще имеет некоторые ограничения.

Протокол NSTextLayoutOrientationProvider определяет интерфейс обеспечивая ориентацию по умолчанию для текста, изложенного в соответствующем объект, в отсутствие явного NSVerticalGlyphFormAttributeNameатрибут. Единственным классом UIKit, который реализует этот интерфейс, является NSTextContainer, реализация по умолчанию которого возвращается NSTextLayoutOrientationHorizontal. Подкласс NSTextContainer, который дескриптор вертикального текста может установить это свойство в NSTextLayoutOrientationVertical для поддержки пользовательского макета логика ориентации.

Источник: UIKit > NSTextLayoutOrientationProvider Ссылка на протокол для iOS

В заключение вы должны начать подклассификацию NSTextContainer, и вам придется иметь дело с NSLayoutManager и NSTextContainer много.


Способ обработки пользовательских изображений

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

  • Отредактируйте обычный текст на скрытый слой с обычным шрифтом. Дайте ему правильный размер для своей ограничивающей рамки.
  • Получить свойства текста, главным образом, высоту текста и межстрочный интервал.
  • Обработать изображение, рисуя каждую строку в обратном порядке снизу вверх, как вы можете видеть на изображении ниже. В результате вы должны получить новый CGImage.
  • Поверните изображение, создав UIImage и установите правильное значение UIImageOrientation.
  • Вставить это изображение в UIScrollView, которое разрешает только горизонтальную прокрутку.

Остерегайтесь, что этот метод отображает весь текст, поэтому не используйте его для очень длинных текстов. Если вам нужно это сделать, вам нужно будет рассмотреть подход к черепице. Смотреть WWDC 2013 > 217 - Изучение прокрутки на iOS 7.

this image

Удачи!

Обновление: (изображение из проекта github)

enter image description here

Ответ 2

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

Вы должны просто установить свойство label/textview transform:

view.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(-M_PI_2)), view.bounds.width, view.bounds.height)

Вам нужно перевести после поворота, потому что представление вращается вокруг его начала (в верхнем левом углу).

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