Замените приложение для iOS Emoji на Twitter с открытым исходным кодом twemoji

Я хочу заменить все стандартные смайлики iOS из UILable или UITextView на twemoji с открытым исходным кодом для твиттеров.

Я не могу найти библиотеку или документацию для этого в iOS. У кого-нибудь есть решение, которое не требует от меня реализации с нуля?

Решение должно быть эффективным и работать в автономном режиме.

2 ответа

Этот вопрос заинтриговал меня, и после небольшого поиска того, как можно было бы заменить все стандартные смайлики iOS на пользовательский набор, я заметил, что даже собственное iOS-приложение Twitter не использует Twemoji:

чирикать

В итоге я пришел к тому же выводу, что и вы:

Я не могу найти библиотеку или документацию для этого в iOS.

Итак, я создал фреймворк в Swift именно для этой цели.

Он делает всю работу за вас, но если вы хотите реализовать свое собственное решение, я опишу ниже, как заменить все стандартные эмодзи на Twemoji.


1. Документируйте все символы, которые могут быть представлены как эмодзи

Есть 1126 базовых символов, которые имеют представления смайликов, и более тысячи дополнительных представлений, образованных последовательностями. Хотя большинство базовых символов ограничено шестью блоками Юникода, все эти блоки, кроме одного, смешаны с символами, не относящимися к эмодзи, и / или неназначенными кодовыми точками. Остальные базовые символы вне этих блоков разбросаны по различным другим блокам.

Моя реализация просто объявляет кодовые точки UTF-32 для этих символов, как value собственностью UnicodeScalar именно это.

2. Проверьте, является ли персонаж эмодзи

В Свифте String содержит коллекцию Character объекты, каждый из которых представляет один расширенный кластер графем. Расширенный кластер графем - это последовательность скаляров Unicode, которые вместе представляют один читаемый человеком 1 символ, что полезно, так как вы можете циклически проходить через Character с строки и обработки их на основе UnicodeScalar s они содержат (вместо того, чтобы перебирать значения строки UTF-16).

Чтобы определить, является ли Character это смайлик, только первый UnicodeScalar имеет большое значение, поэтому достаточно сравнить это значение с таблицей смайликов. Тем не менее, я бы также рекомендовал проверить, если Character содержит Селектор вариаций, и если он есть, убедитесь, что это VS16 - в противном случае персонаж не должен быть представлен как смайлик.

Извлечение UnicodeScalar с из Character требует крошечного взлома:

let c: Character = "A"
let scalars = String(c).unicodeScalars

3. Конвертировать кодовые точки в правильный формат

Изображения Twemoji названы в соответствии с их соответствующими кодами 2, что имеет смысл. Итак, следующим шагом является преобразование Character в строку, эквивалентную имени изображения:

let codePoint = String("").unicodeScalars.first!.value  // 128579
let imageName = String(codePoint, radix: 16)              // "1f643"

Отлично, но это не сработает для флагов или колпачков ключей, поэтому нам придется изменить наш код, чтобы учесть их:

let scalars = String("").unicodeScalars
let filtered = scalars.filter{ $0.value != 0xfe0f }       // Remove VS16 from variants, including keycaps.
let mapped = filtered.map{ String($0.value, radix: 16) }
let imageName = mapped.joined(separator: "-")             // "1f1e7-1f1ea"

4. Заменить эмодзи в строке

Для того, чтобы заменить эмодзи в данном String нам нужно будет использовать NSMutableAttributedString для хранения оригинальной строки и замены смайликов на NSTextAttachment объекты, содержащие соответствующее изображение Twemoji.

let originalString = ""

let attributedString = NSMutableAttributedString(string: originalString)

for character in originalString.characters {
    // Check if character is emoji, see section 2.
    ...

    // Get the image name from the character, see section 3.
    let imageName = ...

    // Safely unwrapping to make sure the image exists.
    if let image = UIImage(named: imageName) {
        let attachment = NSTextAttachment()
        attachment.image = image

        // Create an attributed string from the attachment.
        let twemoji = NSAttributedString(attachment: attachment)

        // Get the range of the character in attributedString.
        let range = attributedString.mutableString.range(of: String(character))

        // Replace the emoji with the corresponding Twemoji.
        attributedString.replaceCharacters(in: range, with: twemoji)
    }
}

Чтобы отобразить полученную атрибутивную строку, просто установите ее как attributedText свойство UITextView / UILabel,

Обратите внимание, что в приведенном выше методе не учитываются составные элементы нулевой ширины или последовательности модификаторов, но я чувствую, что этот ответ уже слишком длинный.


1. Причудливый Character тип, который интерпретирует последовательность объединенных символов региональных индикаторов как один объект, несмотря на то, что он содержит теоретически неограниченное количество скаляров Unicode. Пытаться "".characters.count на детской площадке.

2. Шаблон именования слегка меняется, когда речь идет о соединителях нулевой ширины и селекторах вариаций, поэтому их легче вырезать из имен изображений - см. Здесь.

Легче всего сделать:

1) Загрузите изображения twemoji в ваш проект. 2) Создайте NSDictionary, который соотносит коды смайликов, поддерживаемые iOS, с путями к соответствующим изображениям twemoji:

NSArray *iOSEmojis = @[@"iOSEmoji1",@"iOSEmoji2];
NSDictionary *twemojiPaths = [NSDictionary dictionaryWithObjects:@[@"Project/twemoji1.png",@"Project/twemoji2.png"] andKeys:@[@"iOSEmoji1","iOSEmoji2"]];

3) Код вашего приложения для поиска строк смайликов и отображения twemojis, куда пойдут обычные эмодзи:

for (NSString *emoji in iOSEmojis)
{
    NSString *twemojiPath = [twemojiPaths valueForKey:emoji];
    // Find the position of the emoji string in the text
    // and put an image view there.
    NSRange range = [label.text rangeOfString:emoji];
    NSString *prefix = [label.text substringToIndex:range.location];
    CGSize prefixSize = [prefix sizeWithAttributes: @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14]}];
    CGSize emojiSize = [label.text sizeWithAttributes: @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue" size:14]}];
    CGRect imageViewFrame = CGRectMake(prefixSize.width,label.frame.size.height,emojiSize.width,label.frame.size.height);
    imageViewFrame = [self.view convertRect:imageViewFrame fromView:label];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageViewFrame];
    imageView.image = [UIImage imageWithContentsOfFile:twemojiPath];
}
Другие вопросы по тегам