Display Emoji from unicode in UILabel in iOS - ios

I am working on emoji in chat app.
When someone send me emoji in message it look like this type :- Hello...(worried) how are you(happy)?. Here (worried)and (happy) are assigned keys for emojis.
This is list for emojis and key and value.
dictemoji = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"worried-48.gif",#"(worried)",
#"sad-48.gif",#"(sad)",
#"bandit48.gif",#"(bandit)",
#"wink48.gif",#"(wink)",
#"surprised48.gif",#"(surprised)",
#"smirking48.gif",#"(smirking)",
#"laugh48.gif",#"(laugh)",
#"cool48.gif",#"(cool)",
#"stoned-48.gif",#"(stoned)",
#"smile-48.gif",#"(smile)",
#"nerd-48.gif",#"(nerd)",
#"happy-48.gif",#"(happy)",
#"evil-grin-48.gif",#"(evil-grin)",
#"tongue48.gif",#"(tongue)",
#"lips-sealed-48.gif",#"(lips-sealed)",
#"GIF48.gif",#"(GIF)",
#"dull48.gif",#"(dull)",
nil];
When I received message Hello...(worried) how are you(happy)? I want to saw my emoji instead of (worried)and(happy) in label.
So how can I take emoji instead of those words?
EDIT:-
When someone send me emoji with text message, it will replace with dictionary value :
for (NSString *emojiKey in dictemoji.allKeys)
{
if ([message containsString:emojiKey])
{
message = [message stringByReplacingOccurrencesOfString:emojiKey withString:[dictemoji valueForKey:emojiKey]];
}
}
// helllo(sad)...how are you(smile)...? ----->it will look like helllo(sad-48.gif)...how are you(smile-48.gif)...?
NSLog(#"message updated:%#",message);
cell.textLabel.text=message;
So, I want to display emoji where (sad-48.gif) and (smile-48.gif) printed in label.

Try this. It may help you.
Add one label & write the following code in viewDidLoad :
NSData *dataa = [valueUnicode dataUsingEncoding:NSUTF8StringEncoding];
NSString *valueEmoj = [[NSString alloc] initWithData:dataa encoding:NSNonLossyASCIIStringEncoding];
_lbl.text = valueEmoj;

You have to use like this ;
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:[dictemoji valueForKey:emojiKey]];
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
NSMutableAttributedString *myString= [[NSMutableAttributedString alloc] initWithString:#"My label text"];
[myString appendAttributedString:attachmentString];
cell.attributedText = myString;
hope this will help.

Related

How to detect emoji and change font size

I have text which contains emoji in it, we are able to display it correctly by doing encoding and decoding the string, what I need to achieve is to increase the font size of only emoji in the text like in image below,
I have got an idea to determine the range of all emoji, and supply in NSAttributedString with increased font size. Now am out of idea how can I detect range of emojis in a given string?
Thanks
I have done the same like
let string = "This is emoji Test"
let attributedEmoji = NSMutableAttributedString(string: " \u{1F600}", attributes: [NSFontAttributeName:UIFont.systemFontOfSize(60)])
let attribString = NSMutableAttributedString.init(string: string)
attribString.appendAttributedString(attributedEmoji)
lblEmoji.attributedText = attribString
You can change the font and font size to scale the emoji.
Put all possible Emoji's(Your application uses) into an array.
Search for emoji into string from array.If found apply attributed Emoji.
Write a method that accept emoji code and return attributed emoji text.
Hope this info will help you in better way.
https://github.com/woxtu/NSString-RemoveEmoji
Find out if Character in String is emoji?
you can use it directly like below or
if ([myString containsString:#"😋"])
{
NSLog(#"one");
//change the font size here.
}
else
{
NSLog(#"fk");
//change the font size here.
}
or you can use
[mystring is isEqualToString:"I believe 😋"];
try those. hope this will help to you.
I have made one demo, You can detect emoji from the string like below,
NSString *str = #"this is 😄 and test 😊";
NSArray *arr = [str componentsSeparatedByString:#" "];
for (int i = 0; i < arr.count; i++) {
NSString *temp = [arr objectAtIndex:i];
if ( ![temp canBeConvertedToEncoding:NSASCIIStringEncoding]) {
NSLog(#"%d",i);
NSLog(#"%#",temp); // temp is emoji. You can detect emoji here from your string now you can manage as per your need
}
}
Thanks to all who answered, but none was complete answer though #Raj's suggestion to look NSString-RemoveEmoji helped me to achieve the solution for this, here it is, it works for any kind of emoji
-(NSMutableAttributedString *)getAttributedEmojiString:(NSString *)inputString{
NSMutableArray *__block emojiRange=[[NSMutableArray alloc] init];
[inputString enumerateSubstringsInRange:NSMakeRange(0, [inputString length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock: ^(NSString* substring, NSRange substringRange, NSRange enclosingRange, BOOL* stop) {
if([substring isEmoji]){
[emojiRange addObject:#{#"startrange":#(substringRange.location),#"endrange":#(enclosingRange.length)}];
}
}];
NSMutableAttributedString *mutString=[[NSMutableAttributedString alloc] initWithString:inputString];
[mutString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16.0] range:NSMakeRange(0, mutString.length)];
[emojiRange enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[mutString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:35.0] range:NSMakeRange([obj[#"startrange"] floatValue], [obj[#"endrange"] floatValue])];
}];
return mutString;
}
Description
First find NSRange of all the emoji in the string by using NSString-RemoveEmoji function isEmoji, and store in array.
Supply the fetched range to apply bigger FONT SIZE to characters in the range.
Finally assign the generated attributed text to the label.
self.label.attributedText=[self getAttributedEmojiString:EmojiDecoded(originalText)];
I use two macros to Encode and Decode Emoji's since I need to save these values to server and read through api, below are the macros.
#define Encoded(val) [[val dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]
#define Decoded(val) [[NSString alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:val options:0] encoding:NSUTF8StringEncoding]
#define EmojiEncoded(val) [[NSString alloc] initWithData:[val dataUsingEncoding:NSNonLossyASCIIStringEncoding] encoding:NSUTF8StringEncoding]
#define EmojiDecoded(val) [[NSString alloc] initWithData:[val dataUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding]
Hope it helps anyone who is looking for similar solution.
Cheers, and thanks to all.
This is somewhat late but might be useful for other folks who stumble upon this answer. The secret is to ask Core Text and it knows which characters in the NSAttributedString are emoji characters.
// Build the attributed string as needed
let ns = NSAttributedString(string: s)
// Now create a typesetter and render the line
let typesetter = CTTypesetterCreateWithAttributedString(nsa)
let line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, nsa.length))
// Once you have a line you can enumerate the runs
guard let runs = CTLineGetGlyphRuns(line) as? [CTRun] else {
throw NSError(domain: "CoreText", code: -1, userInfo: nil)
}
// Each run will have a font with specific attributes
print("There are \(runs.count) run(s) in \(ns.string)")
print()
for run in runs {
let charRange = CTRunGetStringRange(run)
let x: NSAttributedString = CFAttributedStringCreateWithSubstring(nil, nsa, charRange)
print(" Chars: '\(x.string)'")
let attributes: NSDictionary = CTRunGetAttributes(run)
let font = attributes["NSFont"] as! CTFont
let traits = CTFontGetSymbolicTraits(font)
print(" Emoji == \(traits.contains(.traitColorGlyphs))")
print()
}

lineBreakMode for multiline attributed string

I have a multiline label that will contain an attributed string. This is the code of the attributed string:
NSString * titleString = #"Title";
NSString * informationString = self.myObject.content;
NSString * allString = [NSString stringWithFormat:#"%#\n\n%#",titleString,informationString];
NSMutableAttributedString* attributedMessage = [[NSMutableAttributedString alloc]initWithString:allString];
NSMutableParagraphStyle* style=[[NSMutableParagraphStyle alloc]init];
style.alignment = NSTextAlignmentLeft;
NSDictionary *attributesTitle = [NSDictionary dictionaryWithObjectsAndKeys:style,NSParagraphStyleAttributeName,[UIColor blackColor],NSForegroundColorAttributeName,[UIColor clearColor],NSBackgroundColorAttributeName,Font(#"OpenSans-Semibold", 17+(int)((self.view.bounds.size.width-290.)/15.)),NSFontAttributeName,nil];
NSMutableParagraphStyle* styleText=[[NSMutableParagraphStyle alloc]init];
styleText.alignment = NSTextAlignmentLeft;
styleText.lineBreakMode = NSLineBreakByTruncatingTail;
NSDictionary *attributesInformation = [NSDictionary dictionaryWithObjectsAndKeys:styleText,NSParagraphStyleAttributeName,[UIColor colorWithRed:91./255 green:91./255 blue:91./255 alpha:1.],NSForegroundColorAttributeName,[UIColor clearColor],NSBackgroundColorAttributeName,[UIFont fontWithName:#"Roboto-Light" size:13.+(int)((self.view.bounds.size.width-290.)/15.)],NSFontAttributeName,nil];
[attributedMessage setAttributes:attributesTitle range:[allString rangeOfString:titleString]];
[attributedMessage setAttributes:attributesInformation range:[allString rangeOfString:informationString]];
In my case the label is shown with ellipse "..." in all the lines. how can i resolve this issue. I want that will be shown only in the last visible line.
The solution that i adopted is
while (newHeight>=heightOfLabel){
remove some letter from the end of the string
calculate new height
}
replace the last three charachter with "..."
and it is done :)
I know that it is not a clean solution but it resolve my issue until finding a clean one.

Multiple text alignment with same label using NSMutableAttributedString on iOS

I want to set Text direction for my label using NSMutableAttributedString. for example, I have chat view, which contains message and time. I want to set left alignment for message and right alignment for time using UILabel.
I have used following code, but it's not working,
NSString *Time = [Functions stringFromGivenDate:msg.time withFormate:#"hh:mm a"];
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#\n%#",msg.text,Time]];
NSDictionary *attrDictionary = #{NSWritingDirectionAttributeName:#[#(NSTextWritingDirectionOverride)]};
[str addAttributes:attrDictionary range:NSMakeRange(msg.text.length+1, Time.length)];
if I understood correctly, this should help:
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.alignment = alignment;// type NSTextAlignment
NSDictionary *attributtes = #{NSParagraphStyleAttributeName : style,};

Code crashing during initialization of NSMutableAttributedString

I need to initialize NsmutableAttributedString with a string productDesc, but the code crashes in the line
attrStrInfoLabel= [[NSMutableAttributedString alloc] initWithString:productDesc];
with error [NSConcreteMutableAttributedString _encodingCantBeStoredInEightBitCFString].
Please advice my code is
NSMutableAttributedString *attrStrInfoLabel;
NSMutableString *productDesc;
productDesc = [NSMutableString stringWithFormat:#"PRODUCT DESCRIPTION:%#", [productDescription objectAtIndex:i]];
attrStrInfoLabel= [[NSMutableAttributedString alloc] initWithString:productDesc];
Try out using NSAttributedString instead of NSMutableString.
Take a look at below Code Sample.
NSMutableAttributedString *attrStrInfoLabel = [[NSMutableAttributedString alloc] init];
NSAttributedString *productDesc = [[NSAttributedString alloc] initWithString:[NSMutableString stringWithFormat:#"PRODUCT DESCRIPTION:%#",[productDescription objectAtIndex:i]];
[attrStrInfoLabel appendAttributedString:productDesc];
Meanwhile check the data in productDescription too. Put some check whether is !nil and has count>0.
The code you posted does not cause the error, but I am going to assume you have an NSLog() call in the following line:
NSLog(#"%#", attrStrInfoLabel);
which should be changed to:
NSLog(#"%#", [attrStrInfoLabel string]);
Initialise it and then append.
NSMutableString *str = [[NSMutableString alloc] init];
[str appendString:YOUR_STRING];

Core Text in UITableviewCell's content overlapping and repeating and superimpose on the other cells

I am using Core Text to add text to UITableviewCell's content but arabic content seems to be overlapping and repeating itself as I scroll and superimpose on the other cells.
I am also using other elements on the page which appear just fine and are not repeating . Just the Core Text seems to be repeating.
I cant figure out why .
Here is my code:
- (CTFontRef)newCustomFontWithName:(NSString *)aFontName
ofType:(NSString *)type
attributes:(NSDictionary *)attributes {
NSString *fontPath = [[NSBundle mainBundle] pathForResource:aFontName ofType:type];
NSData *data = [[NSData alloc] initWithContentsOfFile:fontPath];
CGDataProviderRef fontProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGFontRef cgFont = CGFontCreateWithDataProvider(fontProvider);
CGDataProviderRelease(fontProvider);
CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attributes);
CTFontRef font = CTFontCreateWithGraphicsFont(cgFont, 0, NULL, fontDescriptor);
CFRelease(fontDescriptor);
CGFontRelease(cgFont);
return font;
}
- (CATextLayer *)customCATextLayer:(NSString *)textString {
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:24.f], (NSString *)kCTFontSizeAttribute,
[NSNumber numberWithInt:1], (NSString *)kCTLigatureAttributeName,
nil];
CTFontRef font = [self newCustomFontWithName:#"me_quranKer6"
ofType:#"ttf"
attributes:attributes];
CATextLayer *normalTextLayer = [[CATextLayer alloc] init];
normalTextLayer.font = font;
normalTextLayer.string = textString;
normalTextLayer.wrapped = YES;
normalTextLayer.foregroundColor = [[UIColor blackColor] CGColor];
normalTextLayer.fontSize = 24.f;
normalTextLayer.alignmentMode = kCAAlignmentCenter;
normalTextLayer.frame = CGRectMake(0.f, 10.f, 320.f, 32.f);
CFRelease(font);
return normalTextLayer;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
QuranVersesViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"verseCell"];
Verse *verse = [self.fetchedResultsController objectAtIndexPath:indexPath];
//English Content starts
NSMutableAttributedString * englishAttributedString;
if (!englishAttributedString)
englishAttributedString = [[NSMutableAttributedString alloc] initWithString:#""];
NSMutableAttributedString * englishSubtitleAttributedString;
NSMutableAttributedString * englishVerseAttributedString;
if (!englishVerseAttributedString)
englishVerseAttributedString = [[NSMutableAttributedString alloc] initWithString:verse.english_version];
NSMutableAttributedString * englishFootnoteAttributedString;
if (!englishFootnoteAttributedString)
englishFootnoteAttributedString = [[NSMutableAttributedString alloc] init];
NSString *englishString = #"";
if(verse.subtitle.length>0)
{
NSMutableParagraphStyle *mutParaStyle=[[NSMutableParagraphStyle alloc] init];
[mutParaStyle setAlignment:NSTextAlignmentCenter];
englishSubtitleAttributedString = [[NSMutableAttributedString alloc] initWithString:verse.subtitle];
[englishSubtitleAttributedString addAttributes:[NSDictionary dictionaryWithObject:mutParaStyle
forKey:NSParagraphStyleAttributeName]
range:NSMakeRange(0,[[englishSubtitleAttributedString string] length])];
[englishAttributedString appendAttributedString:englishSubtitleAttributedString];
[englishAttributedString addAttribute:NSFontAttributeName value:[UIFont fontWithName:#"Arial" size:30] range:NSRangeFromString(verse.subtitle)];
NSLog(#"text us %#", englishAttributedString);
}// englishString = [englishString stringByAppendingString:[NSString stringWithFormat:#"%#\n\n", verse.subtitle]];
[englishAttributedString appendAttributedString:englishVerseAttributedString];
englishString = [englishString stringByAppendingString:[NSString stringWithFormat:#"[%#:%#] %#\n", verse.whichSura.sura_no, verse.verse_no, verse.english_version]];
if(verse.footnote.length>0)
englishString = [englishString stringByAppendingString: [NSString stringWithFormat:#"\n%#\n", verse.footnote]];
englishString = [englishString stringByReplacingOccurrencesOfString:#"“" withString:#"\"" ];
englishString = [englishString stringByReplacingOccurrencesOfString:#"_" withString:#"\n" ];
cell.quranVerseEnglishTextView.attributedText = englishAttributedString;
[cell.quranVerseEnglishTextView autoResizeWithMaxWidth:MAX_TEXT_WIDTH];
cell.quranVerseEnglishTextView.backgroundColor = [UIColor clearColor];
//English Content starts
//Arabic Content
CATextLayer *arabicTextLayer = [self customCATextLayer:verse.arabic_version];
[cell.arabicView.layer addSublayer:arabicTextLayer];
return cell;
}
I was facing the same problem until I read up about NSAttributedStrings (made available in iOS 6) on this tutorial here.
The following code will solve your issue:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:info.text attributes:#{ NSFontAttributeName : [UIFont fontWithName:#"Scheherazade" size:32], NSLigatureAttributeName: #2}];
cell.textLabel.attributedText = attributedString;
Out of curiosity, would I be correct to say that you opted to use CoreText because of difficulties in rendering embedded arabic fonts? I ventured the guess because I was attempting to use a similar method as you have done in your code when faced with that exact problem for a Quran app that I'm currently developing. If this so then I can confirm that using NSAttributedString also solves the problem. If you notice in the code above I've also set the NSLigatureAttributeName to 2 which according to the official Apple Class Reference Documentation means 'all ligatures'. Just note that this is something that I'm currently testing and I have yet to see the effects of this but I know that ligatures is a common problem in the rendering of some arabic fonts on certain platforms.
While on the subject, another common problem you may be facing is the line-spacing of arabic text and the slight overlapping of multi-line text and I've found that NSAttributedString can also be a good solution when used together with NSParagraphStyle (Hooray again for NSAttributedString!). Simply modify the above code as below:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:info.text attributes:#{ NSFontAttributeName : [UIFont fontWithName:#"Scheherazade" size:32], NSLigatureAttributeName: #2}];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:20];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [info.text length])];
cell.textLabel.attributedText = attributedString;
Hope this helps you or anyone else out there!
EDIT - Adding this helpful post on Common Mistakes With Adding Custom Fonts to Your iOS App for reference as a "checklist" when adding custom fonts on iOS.
Actually fixed the issue myself by adding the following line in cellforRowAtIndexPath:
if (cell == nil)
{
cell = [[QuranVersesViewCell alloc] init];
.....
and also did all the initialization and setting only when the cell was nil. And MOST importantly tagged the view layer and set the text for only the matching tagged view...

Resources