Кернинг в iOS UITextView

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

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

Например:

Есть ли обходной путь, чтобы это исправить?

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

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

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

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

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

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

 Cocoanetics16 дек. 2012 г., 18:11
Какие'Приписываемая строка, которую вы пытаетесь? В моем эксперименте я смог указать отрицательное значение для атрибута значения кернинга, чтобы переключать буквы вместе: [attributetedString addAttribute: NSKernAttributeName value: [NSNumber numberWithFloat: -10] range: NSMakeRange (0, 3)];
 Rob Napier14 нояб. 2012 г., 23:12
Если так, можете ли вы опубликовать это, чтобы мы могли обмануть?
 hukir05 нояб. 2012 г., 21:40
Вы можете использовать NSAttributedStrings. Будет работать только если вы можете требовать iOS6, хотя.
 Anthony Mattox05 нояб. 2012 г., 22:29
Хороший звонок. Я забыл также упомянуть, что из-заошибка» Кернинг не работает с NSAttributedString в UITextView.
 Rob Napier14 нояб. 2012 г., 22:52
Когда вы говорите этоошибка, значит ли это, что выВы открыли радар на сайте bugreport.apple.com?

Ответы на вопрос(6)

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

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

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

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

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

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

 Anthony Mattox09 нояб. 2012 г., 17:14
Спасибо Марк, я взглянул на этот проект. Я думаю это'ы относительно спорный теперь, что большинство элементов UIKit поддерживают приписываемые строки. Мне также нужен многострочный ввод текста, поэтому я нене могу извлечь из этого многое.
Решение Вопроса

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

NSString *css = @"*{text-rendering: optimizeLegibility;}";
NSString *html = [NSString stringWithFormat:@"%@Your HTML Text", 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.

 Mark Granoff14 нояб. 2012 г., 22:53
Очень умно. И подлый. :-)
 mikemike39628 мая 2013 г., 15:29
Отличный кусок кода!
 nielsbot15 нояб. 2012 г., 20:11
и на самом деле я незапутать селектор, я просто использовалNSSelectorFromString(selectorName)
 Mike Abdullah15 нояб. 2012 г., 16:04
Обратите внимание, что проверка-respondsToSelector: это лучшая проверка для удаляемого метода, чем@try/@catch блок. Обработчик исключений больше подходит для противодействия тому, что вы потенциально можете передать то, что API не делаетт ручки
 nielsbot15 нояб. 2012 г., 20:10
У меня есть приложения, которые поставляются с использованием этого трюка - но я использовал -respondsToSelector:, а не @ try / @ catch
 Anthony Mattox15 нояб. 2012 г., 18:30
Спасибо @ 0xced, хороший трюк. Я предполагал, что в процессе проверки магазина приложений они запускают приложение в среде, которая отслеживает все вызовы API, чтобы они могли проверять даже динамически генерируемые сообщения. Кто-нибудь может подтвердить, что это пробьется?

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

 Anthony Mattox15 нояб. 2012 г., 19:58
Тот'это правда, 'NSAttributedStringЭто хорошо работает для большинства форматирования текста, но, как я уже упоминал в этом вопросе, из-за того, что, по-видимому, является ошибкой, кернинг не работает в UITextViews. Хотя вы можете использовать свойство приписанной строки для настройки кернинга для конкретного Парижа, нет возможности включить шрифт.встроенный кернинг.

Попробуй это:

[textView_ setValue:@"hello, world" forKey:@"contentToHTMLString"];

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

Там'Нет необходимости прибегать к частным методам. Вы можете легко подделать его, динамически изменяя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];
}
 Anthony Mattox15 мар. 2014 г., 14:56
Этот ответ не касается вопроса об использовании шрифтавстроенный кернинг, а не о том, как устанавливать значения кернинга для определенных пар. Установка атрибута kern в число, как вы 'Мы предложили бы настроить отслеживание всей строки текста.

Ваш ответ на вопрос