Вертикальное центрирование текста в UITextView неправильной формы

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

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

Подходы, которые я видел, предлагают скорректировать contentInset текстового представления после того, как текст был выложен, и окончательная высота известна. (Например, этот вопрос). Однако, в случае области неправильной формы высота текста после его размещения будет зависеть от того, откуда начинается расположение области.

Подход, который я рассмотрел, состоит в том, чтобы повторить процесс компоновки, пока не будет достигнут удовлетворительный макет. У кого-нибудь был успех с таким подходом? Одна из сложностей заключается в том, что я не определился, как определить, был ли весь текст отрисован в представлении (т. Е. Достаточно ли места для размещения всего текста) - есть ли способ запросить, все ли содержимое был 'отрендерен' при использовании UITextView?

Наконец: это только для отображения текста - нет необходимости разрешать пользователю редактировать содержимое представления. Было бы CoreText может быть лучше подход в этом случае?

Я довольно новичок в разработке для iOS, поэтому, если я что-то возмутительно делаю, это также полезно знать!

Спасибо!

let boundingRect = CGRect(...)
let textView = UITextView(frame: boundingRect)

textView.editable = false
view.addSubview(textView)

let verticalInset:CGFloat = <some value>

let width = boundingRect.width
let height = boundingRect.height
let textBounds = CGSize(width: width, height:height - 2*verticalInset)
textView.bounds = textBounds

let exclusionRect = CGRect(x:0, y:-verticalInset, width:width, height:height)

let textRegion = UIBezierPath(ovalInRect: exclusionRect)    
let exclusionPath = UIBezierPath(rect:exclusionRect)
exclusionPath.appendPath(textRegion.bezierPathByReversingPath())

textView.textContainer.exclusionPaths = [exclusionPath]

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center

let attributes = [NSParagraphStyleAttributeName: paragraphStyle]
let formattedContent = NSAttributedString(string: "....", attributes:attributes)

textView.attributedText(formattedContent)

Вот изображение, чтобы помочь визуализировать выше, если полезно:пример

2 ответа

Если вы размещаете текст в прямоугольной области, его легко отцентрировать по вертикали, сместив его вверх или вниз. Если область не прямоугольная, как в вашем случае, это невозможно, так как текст не обязательно помещается в форму после ее вертикального смещения.

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

Чтобы сделать это с помощью Core Text, вы можете создать CTFrame для текстового макета, как это:

let text:NSAttributedString = ... // The text to render
let path:CGPath = ... // Bounds the shape in which the text is rendered
let framesetter = CTFramesetterCreateWithAttributedString(text)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)

С этим frame, вы можете проверить, была ли отрисована вся строка:

let range = CTFrameGetVisibleStringRange(frame)
if text.length == range.length {
  // Fits
}

И для рендеринга текста:

let ctx:CGContext = ... 
CTFrameDraw(renderFrame, ctx)

Если вам нужно больше деталей о отображаемом тексте, вы можете использовать CTFrameGetLines чтобы получить CTLineс из frame, Затем, используя CTFrameGetLineOrigins а также CTLineGetBoundsWithOptions с возможностью UseGlyphPathBounds или же UseOpticalBoundsВы можете рассчитать оптические границы для отдельных линий. Это позволяет более точную вертикальную регулировку. (Приготовьтесь к некоторой линейной алгебре, преобразования системы координат, которые необходимы для непосредственного использования CoreText с CoreGraphics, могут быть немного утомительными).

Я не могу предложить фантастический ответ здесь.

Тем не менее, я только что опробовал YYText. У этого есть "YYLabel", который поддерживает вертикальное выравнивание текста и пути исключения. Взгляните на их демонстрационный проект, в частности на строку "TextAttributes1" в их табличном представлении, которое демонстрирует.

Другие вопросы по тегам