Отображение пропорционально расположенных чисел (вместо моноширинных/табличных) на iOS

Я отображаю числа в iOS (с целью 7 и выше), сохраняя их в NSAttributedString и отображая с помощью «drawAtPoint:». Я использую Helvetica Neue.

Я заметил, что нарисованные таким образом цифры не пропорциональны — все глифы имеют одинаковую ширину. Даже маленькая «1» занимает то же место, что и «0».

Тест это подтверждает:

for(NSInteger i=0; i<10; ++i)
{
  NSString *iString = [NSString stringWithFormat: @"%d", i];
  const CGSize iSize = [iString sizeWithAttributes: [self attributes]];
  NSLog(@"Size of %d is %f", i, iSize.width);
}

С, в другом месте:

-(NSDictionary *) attributes
{
  static NSDictionary * attributes;
  if(!attributes)
  {
    attributes = @{
                   NSFontAttributeName: [UIFont systemFontOfSize:11],
                   NSForegroundColorAttributeName: [UIColor whiteColor]
                   };
  }
  return attributes;
}

Полученные глифы все имеют одинаковую ширину — 6,358 пункта.

Есть ли какой-нибудь параметр рендеринга, который я могу включить, чтобы включить глифы с пропорциональными цифрами? Есть ли другой шрифт (в идеале похожий на Helvetica Neue), который поддерживает глифы с пропорциональными цифрами (в идеале, встроенные)? Что-нибудь еще?

Спасибо.


person Benjohn    schedule 13.11.2013    source источник
comment
Обсуждается использование пропорциональных стихов, табличных (другой термин для моноширинных) цифр и цифр по адресу ссылка. При поиске по этой терминологии я нашел это ссылка на рендеринг шрифтов iOS 7, что, я думаю, позволит мне самому ответить на этот вопрос. Я обновлю, когда закончу.   -  person Benjohn    schedule 14.11.2013
comment
Эта ссылка в формате PDF содержит необходимый код. Важно знать, что для использования этих функций необходимо #import <CoreText/CoreText.h>: здесь определяются символы.   -  person Benjohn    schedule 14.11.2013


Ответы (1)


iOS 7 позволяет указывать шрифты с помощью UIFontDescriptor экземпляров. Затем из дескриптора получается экземпляр UIFont.

Учитывая UIFontDescriptor, также можно получить его настройку, которая изменяет некоторые характеристики, используя метод [fontDescriptor fontDescriptorByAddingAttributes: attibutes], где attributes — это NSDictionary атрибутов шрифта.

Apple документирует атрибуты в UIFontDescriptor справочнике.

Из ссылки один конкретный атрибут дескриптора шрифта UIFontDescriptorFeatureSettingsAttribute позволяет вам предоставить «массив словарей, представляющих настройки функций шрифта не по умолчанию. Каждый словарь содержит UIFontFeatureTypeIdentifierKey и UIFontFeatureSelectorIdentifierKey».

Документация по UIFontFeatureTypeIdentifierKeys и UIFontFeatureSelectorIdentifierKeys находится в документации Apple Font Registry. Конкретный случай пропорциональных цифр рассматривается в этом PDF слайдов презентации Apple, поэтому я только что поднял это.

Этот код возьмет существующий экземпляр UIFont и вернет вам новый экземпляр с пропорциональными цифрами:

// You'll need this somewhere at the top of your file to pull
// in the required constants.
#import <CoreText/CoreText.h>

…

UIFont *const existingFont = [UIFont preferredFontForTextStyle: UIFontTextStyleBody];
UIFontDescriptor *const existingDescriptor = [existingFont fontDescriptor];

NSDictionary *const fontAttributes = @{
 // Here comes that array of dictionaries each containing UIFontFeatureTypeIdentifierKey 
 // and UIFontFeatureSelectorIdentifierKey that the reference mentions.
 UIFontDescriptorFeatureSettingsAttribute: @[
     @{
       UIFontFeatureTypeIdentifierKey: @(kNumberSpacingType),
       UIFontFeatureSelectorIdentifierKey: @(kProportionalNumbersSelector)
      }]
 };

UIFontDescriptor *const proportionalDescriptor = [existingDescriptor fontDescriptorByAddingAttributes: fontAttributes];
UIFont *const proportionalFont = [UIFont fontWithDescriptor: proportionalDescriptor size: [existingFont pointSize]];

Вы можете добавить это как категорию на UIFont, если хотите, и т. д.

Редактировать примечание: спасибо Крису Швердту за улучшения.

person Benjohn    schedule 14.11.2013
comment
+1 Не забудьте импортировать CoreText для этих констант. - person Tricertops; 14.11.2013
comment
Спасибо, Мартин, я внесу изменения в код, чтобы добавить это, так как сначала я почесал голову! - person Benjohn; 14.11.2013
comment
Это не работает для меня, все числа, кроме 1, кажутся пропорциональными. Любые идеи? - person Tyler Pfaff; 13.03.2014
comment
Может быть, это просто шрифт, который ты используешь, @TylerPfaff? Я не проверял ширину каждого глифа, так что, возможно, я получаю то же самое — хотя, похоже, выглядит нормально :-) - person Benjohn; 14.03.2014
comment
Значения для UIFontFeatureTypeIdentifierKey и UIFontFeatureSelectorIdentifierKey можно найти в SFNTLayoutTypes.h, который также ссылается на документацию по реестру шрифтов Apple. . - person Chris Schwerdt; 15.03.2014
comment
Также вы можете удалить ключ kCharacterAlternativesType. Я полагаю, что он использовался в том примере форматирования времени для замены квадратного символа двоеточия закругленным символом двоеточия и не влияет на интервал между числами. - person Chris Schwerdt; 15.03.2014
comment
@ChrisSchwerdt Спасибо. Я отредактирую ответ, включив в него ваши предложения, если только вы не предпочтете и не получите кредит на редактирование? - person Benjohn; 17.03.2014
comment
@TylerPfaff Я думаю, что для шрифта Helvetica Neue, даже с пропорциональными цифрами, уже только 1 глиф. Тем не менее, это все еще большое улучшение по сравнению с полностью табличными цифрами. Другие шрифты, поддерживающие пропорциональные цифры, могут отличаться. (p.s. – пропорционально ширина глифов действительно различается, табличная или фиксированная ширина или моноширина i> там, где они не отличаются). - person Benjohn; 22.10.2014
comment
Эта опция работает, только если вы используете шрифт, поддерживающий эту функцию. Если вы используете собственный шрифт, это может не сработать. Параметры, поддерживаемые шрифтом, можно проверить примерно так: NSLog(@"%@", CTFontCopyFeatures ( ( __bridge CTFontRef ) myFont )); - person Anthony Mattox; 03.03.2015