How to Display the Emoji and Special Characters in Uilabel and Uitextviews

How to display the emoji and special characters in UIlabel and UItextviews?

Emoji characters are in unicode plane 1 and thus require more than 16 bits to represent a code point. Thus two UTF8 representations or one UTF32 representation. Unicode is actually a 21-bit system and for plane 0 characters (basically everything except emoji) 16 bits is sufficient and we get by using 16 bits. Emoji need more than 16 bits.

"Youtube\ud83d\ude27\ud83d\ude2e\ud83d\ude2f\ud83d". is invalid, it is part of a utf16 unicode escaped string, the last \ud83d is 1/2 of an emoji character.

Also, inorder to create a literal string with the escape character "\" the escape character must be escaped: "\\".

NSString *emojiEscaped = @"Youtube\\ud83d\\ude27\\ud83d\\ude2e\\ud83d\\ude2f";
NSData *emojiData = [emojiEscaped dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiString = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
NSLog(@"emojiString: %@", emojiString);

NSLog output:

emojiString: Youtube/p>

The emoji string can also be expressed in utf32:

NSString *string = @"\U0001f627\U0001f62e\U0001f62f";
NSLog(@"string: %@", string);

NSLog output:

string1: /p>

Set text(with emojis, special chars, links) in UILabel, and link should be clickable

I needed this kind of linked text for another project last month. I created a custom UITableViewCell with a UITextView object in the cell, subclassed to a custom UITextView subclass. I just made a quick demo project and put it up on git for you now. Feel free to use it.

github.com/fareast555/MPC_LinkedTextView

The basic secret sauce for using text links is the NSLinkAttributeName attribute in the mutable text, and telling the system to handle links.

- (void)updateTextViewWithFullText:(NSString *)fullText linkTriggerText:(NSString *)triggerText linkURLString:(NSString *)urlString
{
//Create a mutable string based on the full text
NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc]initWithString:fullText attributes:nil];

//Add the link attribute across the range of the target text
[mutableString addAttribute:NSLinkAttributeName value:urlString range:[fullText rangeOfString:triggerText]];

//Add any other font or color bling as needed
[mutableString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:18 weight:UIFontWeightMedium] range:NSMakeRange(0, [fullText length])];

//Set the mutable text to the textfield
[self setAttributedText: mutableString];
}

#pragma mark - UITextViewDelegate

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction
{
return YES;
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return NO;
}

And for textviews, you'll find it easier to use auto layout if you turn off scrolling.

#pragma mark - Configure
- (void)_configureTextView
{
self.delegate = self;
[self setEditable:NO];
[self setSelectable:YES];
[self setScrollEnabled:NO];
[self setUserInteractionEnabled:YES];
[self setDataDetectorTypes:UIDataDetectorTypeLink];
self.scrollIndicatorInsets = UIEdgeInsetsZero;
}

Screenshot of table view

Detect if a user has typed an emoji character in UITextView

Over the years these emoji-detecting solutions keep breaking as Apple adds new emojis w/ new methods (like skin-toned emojis built by pre-cursing a character with an additional character), etc.

I finally broke down and just wrote the following method which works for all current emojis and should work for all future emojis.

The solution creates a UILabel with the character and a black background. CG then takes a snapshot of the label and I scan all pixels in the snapshot for any non solid-black pixels. The reason I add the black background is to avoid issues of false-coloring due to Subpixel Rendering

The solution runs VERY fast on my device, I can check hundreds of characters a second, but it should be noted that this is a CoreGraphics solution and should not be used heavily like you could with a regular text method. Graphics processing is data heavy so checking thousands of characters at once could result in noticeable lag.

-(BOOL)isEmoji:(NSString *)character {

UILabel *characterRender = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
characterRender.text = character;
characterRender.backgroundColor = [UIColor blackColor];//needed to remove subpixel rendering colors
[characterRender sizeToFit];

CGRect rect = [characterRender bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef contextSnap = UIGraphicsGetCurrentContext();
[characterRender.layer renderInContext:contextSnap];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGImageRef imageRef = [capturedImage CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

BOOL colorPixelFound = NO;

int x = 0;
int y = 0;
while (y < height && !colorPixelFound) {
while (x < width && !colorPixelFound) {

NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

CGFloat red = (CGFloat)rawData[byteIndex];
CGFloat green = (CGFloat)rawData[byteIndex+1];
CGFloat blue = (CGFloat)rawData[byteIndex+2];

CGFloat h, s, b, a;
UIColor *c = [UIColor colorWithRed:red green:green blue:blue alpha:1.0f];
[c getHue:&h saturation:&s brightness:&b alpha:&a];

b /= 255.0f;

if (b > 0) {
colorPixelFound = YES;
}

x++;
}
x=0;
y++;
}

return colorPixelFound;

}

Getting a normal looking unicode down arrow in a UILabel like this ⬇

Displaying some characters as "Emojis" is a feature which is e.g. (controversially) discussed here: https://devforums.apple.com/message/487463#487463 (requires Apple Developer login). This feature was introduced in iOS 6.

A solution (from https://stackoverflow.com/a/13836045/1187415) is to append the Unicode "Variation selector" U+FE0E, e.g.

self.myLabel.text = @"\u2B07\uFE0E";
// or:
self.myLabel.text = @"⬇\uFE0E";

Note that on iOS <= 5.x, the Variation selector is not necessary and must not be used, because iOS 5 would display it as a box.

In Swift it would be

myLabel.text = "⬇\u{FE0E}"


Related Topics



Leave a reply



Submit