#ios #swift #core-text #arabic-support
#iOS #swift #основной текст #Арабский-поддержка
Вопрос:
Я пытался следовать руководству по CoreText и тому, как рисовать текст, и я реализовал эту функцию в своем CustomView.
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
let path = CGMutablePath()
path.addRect(bounds)
let attrString = NSAttributedString(string: "Hello World")
let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, nil)
CTFrameDraw(frame, context)
}
Он отлично работает, когда текст короткий, но когда текст становится более 10 тыс. букв, он отображается неправильно. Есть ли какое-либо решение для этого?
ПРИМЕЧАНИЕ: это происходит, когда текст на арабском языке, а не на английском.
Вот рендеринг, когда текст маленький:
Вот текстовый рендеринг, когда количество текста слишком велико, превышает 10 КБ, он выглядит разрозненным и перевернутым:
Комментарии:
1. Это настоящая ошибка. Я воспроизвел его точно так, как вы описываете, где-то около 10 тысяч букв. Я вижу ту же проблему, если вы пропустите CTFramesetter и используете CTLine и CTTypesetter напрямую. Кроме «сделай свои струны короче», я не уверен, что здесь можно сделать, кроме как поговорить с Apple. Я бы, наверное, использовал для этого DTS, если они у вас остались в этом году. (нажмите «Поддержка на уровне кода» на панели «Учетная запись» по адресу developer.apple.com ) Это действительно интересная ошибка.
2. Привет @RobNapier, большое спасибо за ваш повтор, как вы рекомендовали, я отправил проблему в DTS, и они ответили следующим: в конкретном примере, который вы предоставили, на самом деле может быть не столько размер текста, сколько единственное английское слово в середине текста, котороеможет потребовать дополнительной обработки в Юникоде. Но по умолчанию те части CoreText, которые отображают сложный Юникод, по умолчанию отключены, чтобы избежать низкой производительности и других потенциальных проблем. Это контролируется kCTTypesetterOptionAllowUnboundedLayout (по умолчанию false) Опция набора текста.
3. @RobNapier, итак, как я могу включить такое значение, и, как вы знаете, я не использовал класс Typesetter?
4. Я воспроизвел эту проблему, используя текст из istizada.com/arabic-lorem-ipsum (многократное копирование абзаца). В нем определенно не должно было быть текста со смешанным биди (ltr и rtl). И это определенно происходит, когда я пересекаю определенный размер, поэтому я не верю их теории «единого английского слова». Но kCTTypesetterOptionAllowUnboundedLayout, похоже, исправляет это. Я взломал свой тестовый пример, и он не выполняет правильную компоновку, но я напишу правильный пример позже этим утром. (Обратите внимание, что я думаю
attrString.draw(in: rect)
, что здесь будет работать использование вместо основного текста, но я понимаю, что вы хотите изучить CT)5. Да, я тоже не согласен с ними по поводу этой строки «одно английское слово», большое спасибо @RobNapier
Ответ №1:
Основываясь на ваших отзывах от Apple, кажется, что CTFramesetter отключает расширенный макет, когда строка длиннее определенного размера. (Их предположение о том, что это связано с тем, что текст со смешанным направлением звучит неправильно; я определенно воспроизвел это только на арабском языке.)
Чтобы исправить это, вам необходимо создать фреймсеттер с пользовательским набором текста, который всегда выполняет расширенный макет (kCTTypesetterOptionAllowUnboundedLayout). К счастью, это просто.
Сначала создайте пользовательский набор текста, а затем используйте его для создания набора фреймов:
let typesetterOptions = [kCTTypesetterOptionAllowUnboundedLayout: true] as CFDictionary
let typesetter = CTTypesetterCreateWithAttributedStringAndOptions(attrString,
typesetterOptions)!
let framesetter = CTFramesetterCreateWithTypesetter(typesetter)