Подтвердить что ты не робот

Кернинг в iOS UITextView

Для того, что, по-видимому, является "ошибкой", UITextView, похоже, не поддерживает кернинг, как другие элементы UIKit. Есть ли способ обхода работы кернинга?

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

Пример:

enter image description here

Есть ли способ обхода проблемы?

Один простой обходной путь, который я обнаружил, - добавить стили css в UITextView, которые позволяют кернинг. Если я использую недокументированный метод setContentToHTMLString:, я могу ввести css в секретный веб-просмотр в текстовом представлении.

NSString *css = @"*{text-rendering: optimizeLegibility;}";
NSString *html = [NSString stringWithFormat:@"<html><head><style>%@</style></head><body>Your HTML Text</body></html>", css];
[textView performSelector:@selector(setContentToHTMLString:) withObject:html];

Это немедленно устраняет проблему; однако, похоже, что это отклонит приложение. Есть ли безопасный способ прокрасить некоторые CSS в текстовое представление?

Другие методы, с которыми я экспериментировал, включают:

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

Подклассификация a UITextView и рендеринг текста вручную с помощью основного текста. Это сложнее, чем я надеялся, потому что все элементы выбора тоже нужно переконфигурировать. Из-за UITextView частных подклассов UITextPosition и UITextRange это огромная боль в попке, если не совсем невозможно.

4b9b3361

Ответ 1

Вы правы, что ваше приложение, вероятно, будет отклонено с помощью @selector(setContentToHTMLString:). Однако вы можете использовать простой трюк для динамического создания селектора, чтобы он не обнаруживался во время проверки.

NSString *css = @"*{text-rendering: optimizeLegibility;}";
NSString *html = [NSString stringWithFormat:@"<html><head><style>%@</style></head><body>Your HTML Text</body></html>", css];
@try {
    SEL setContentToHTMLString = NSSelectorFromString([@[@"set", @"Content", @"To", @"HTML", @"String", @":"] componentsJoinedByString:@""]);
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [textView performSelector:setContentToHTMLString withObject:html];
    #pragma clang diagnostic pop
}
@catch (NSException *exception) {
    // html+css could not be applied to text view, so no kerning
}

Обернув вызов внутри блока @try/@catch, вы также убедитесь, что ваше приложение не будет сбой, если метод setContentToHTMLString: будет удален в будущей версии iOS.

Использование частных API обычно не рекомендуется, но в этом случае я считаю, что вполне разумно использовать небольшой взлом для перезаписи UITextView с CoreText.

Ответ 2

Попробуйте следующее:

[textView_ setValue:@"hello, <b>world</b>" forKey:@"contentToHTMLString"];

Он работает в моем тесте. Конечно, я не пробовал его в магазине приложений.

Ответ 3

После небольшого исследования я обнаружил, что причиной отсутствия Кернинга является то, что UITextView внутренне использует UIWebDocumentView, который по умолчанию отключил Кернинг.

Некоторые сведения о внутренней работе UITextView: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/

К сожалению, нет санкционированного метода, позволяющего Кернинг, я бы определенно посоветовал не использовать взломать с помощью камуфляжного селектора.

Здесь мой радар, я предлагаю вам обмануть его: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/

В этом я утверждаю, что при настройке текста в UITextView через setAttributedText мы, разработчики, ожидаем, что кернинг будет включен по умолчанию, потому что именно так он будет наиболее точно соответствовать результату рендеринга текста через CoreText.

Ответ 4

Вы посмотрели здесь: https://github.com/AliSoftware/OHAttributedLabel? Если посмотреть на этот проект, похоже, что в магазине приложений есть несколько приложений, которые используют разметку (предоставленную этим классом). Возможно, вы можете использовать этот класс или получить от него некоторые идеи реализации. Возможно, ваше приложение as-is пройдет.

Ответ 5

С iOS6, UITextView имеет новый атрибут attributedText, которому вы можете назначить NSAttributedString. Я не пробовал, но было бы интересно посмотреть, получится ли вам кернинг, если вы установите этот атрибут вашего текстового вида, а не атрибут text. И это добавляет преимущество публичного интерфейса.

Ответ 6

Не нужно прибегать к частным методам. Вы можете легко подделать его, динамически изменяя свойство attributedText текстового поля каждый раз, когда текст изменяется, подписываясь на уведомление UITextFieldTextDidChangeNotification:

- (void)viewDidLoad {
    // your regular stuff goes here
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChangeNotification:) name:UITextFieldTextDidChangeNotification object:nil];
}


- (void)textDidChangeNotification:(NSNotification *)notification {
    // you can of course specify other attributes here, such as font and text color
    CGFloat kerning = -3.; // change accordingly to your desired value
    NSDictionary *attributes = @{
                                 NSKernAttributeName: @(kerning),
                                 };
    UITextField *textField = [notification object];
    textField.attributedText = [[NSAttributedString alloc] initWithString:textField.text attributes:attributes];
}