Расстановка переносов в iOS с помощью TextKit и выровненного текста

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

let paragraph = NSMutableParagraphStyle()
paragraph.alignment = .justified
paragraph.lineBreakMode = .byWordWrapping
paragraph.hyphenationFactor = 0.85 //here goes the black magic :)

Проблема в том, что выровненный текст без переносов выглядит ужасно, потому что растягивает пространство между буквами (а не словами). Все выглядит нормально, если расстановка переносов работает. Но вот еще одна проблема - перенос переносов применяется к тексту по правилам языка, предпочитаемого текущим телефоном. Это означает, что если предпочтительный язык телефона - английский, а текст - кириллица (например, русский или украинский язык), расстановка переносов вообще не применяется и возникает проблема с растянутым текстом. Вот как выглядит эта проблема:

«Растянутый

Изменение предпочтительного языка телефона на язык текстов приводит к тому, что нативная расстановка переносов работает нормально, а выровненный текст также отображается правильно:

Красиво оформленный текст

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

import NaturalLanguage

extension String {
    func dominantLanguage() -> Locale? {
        let languageRecognizer = NLLanguageRecognizer()
        languageRecognizer.processString(self)

        if let code = languageRecognizer.dominantLanguage?.rawValue {
            let language = Locale.init(identifier: code)
            return language
        } else if let code = languageRecognizer.languageHypotheses(withMaximum: 3).sorted(by: { (arg0, arg1) -> Bool in
            return arg0.value > arg1.value
            }).first?.key.rawValue {
            let language = Locale.init(identifier: code)
            return language
        } else {
            return nil
        }
    }
}

let locale = "qwerty".dominantLanguage()

Но с этим решением есть другая проблема: 1) Оно не работает на 100% правильно. Например, если текст начинается с таблицы (как на снимках экрана выше), languageRecognizer.dominantLanguage возвращает nil, а languageHyphoteses может возвращать неправильный языковой стандарт. Я могу вообще не полагаться на это. 2) Это своего рода хитрость, позволяющая каждый раз менять предпочтительный язык приложения.

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

Кроме того, я обнаружил, что расстановку переносов (на любом языке текста) и выровненный текст можно легко сделать с помощью WebView и CSS -webkit-hyphens, но я действительно не хочу погружаться в работу с WebView, как и CoreText (не подходит для других целей моего приложения). Есть идеи, как добиться таких результатов с помощью TextKit? Ищу надежные решения. Спасибо.


person Igor Prusyazhnyuk    schedule 01.06.2020    source источник
comment
Я не думаю, что есть универсальное решение проблемы. Мое лучшее предположение - расширить логику dominantLanguage() и предварительно обработать строку перед ее передачей в languageRecognizer.processString(PRE_PROCESSED_STRING). Есть несколько API, которые могут помочь вам, например, разбить строку на абзацы, и вы можете запускать функцию languageRecognizer.dominantLanguage? для абзацев, пока не найдете правильное значение. Я почти уверен, что это решение повлияет на производительность, но оно поможет найти правильный доминирующий язык.   -  person dive    schedule 07.06.2020
comment
Привет, я думаю, что iOS автоматически справится с этим. Просто используйте UITextView вместо UILabel. Обратитесь: stackoverflow.com/questions/19709465/ Обращаться вручную очень тяжело. Есть много языков, на которых вы не знаете, какое значение должно быть правильным.   -  person King.lbt    schedule 08.06.2020
comment
@ King.lbt Я не использую UILabel. Я использую UITextView.   -  person Igor Prusyazhnyuk    schedule 09.06.2020


Ответы (1)


Использование UITextView вместо UILabel - это способ сделать эту работу правильной.

Параметр hyphenationFactor (либо как атрибут NSParagraphStyle, либо как свойство NSLayoutManager) должен работать должным образом. - https://stackoverflow.com/a/19766990/6570914

person Denis Kakačka    schedule 08.06.2020
comment
Я не использую UILabel. Я использую UITextView - person Igor Prusyazhnyuk; 09.06.2020