I have a UITextView and I need to detect if a user enters an emoji character.
I would think that just checking the unicode value of the newest character would suffic
if your do not want your keyboard to show emoji you can use
YOURTEXTFIELD/YOURTEXTVIEW.keyboardType = .ASCIICapable
This will show a keyboard with no emoji
Here is the emoji detection method in Swift. It works fine. Hope it will help others.
func isEmoji(_ character: String?) -> Bool {
if character == "" || character == "\n" {
return false
}
let characterRender = UILabel(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
characterRender.text = character
characterRender.backgroundColor = UIColor.black
characterRender.sizeToFit()
let rect: CGRect = characterRender.bounds
UIGraphicsBeginImageContextWithOptions(rect.size, true, 0.0)
if let contextSnap:CGContext = UIGraphicsGetCurrentContext() {
characterRender.layer.render(in: contextSnap)
}
let capturedImage: UIImage? = (UIGraphicsGetImageFromCurrentImageContext())
UIGraphicsEndImageContext()
var colorPixelFound:Bool = false
let imageRef = capturedImage?.cgImage
let width:Int = imageRef!.width
let height:Int = imageRef!.height
let colorSpace = CGColorSpaceCreateDeviceRGB()
let rawData = calloc(width * height * 4, MemoryLayout<CUnsignedChar>.stride).assumingMemoryBound(to: CUnsignedChar.self)
let bytesPerPixel:Int = 4
let bytesPerRow:Int = bytesPerPixel * width
let bitsPerComponent:Int = 8
let context = CGContext(data: rawData, width: Int(width), height: Int(height), bitsPerComponent: Int(bitsPerComponent), bytesPerRow: Int(bytesPerRow), space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue)
context?.draw(imageRef!, in: CGRect(x: 0, y: 0, width: width, height: height))
var x:Int = 0
var y:Int = 0
while (y < height && !colorPixelFound) {
while (x < width && !colorPixelFound) {
let byteIndex: UInt = UInt((bytesPerRow * y) + x * bytesPerPixel)
let red = CGFloat(rawData[Int(byteIndex)])
let green = CGFloat(rawData[Int(byteIndex+1)])
let blue = CGFloat(rawData[Int(byteIndex + 2)])
var h: CGFloat = 0.0
var s: CGFloat = 0.0
var b: CGFloat = 0.0
var a: CGFloat = 0.0
var c = UIColor(red:red, green:green, blue:blue, alpha:1.0)
c.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
b = b/255.0
if Double(b) > 0.0 {
colorPixelFound = true
}
x+=1
}
x=0
y+=1
}
return colorPixelFound
}
Another solution: https://github.com/woxtu/NSString-RemoveEmoji
Then, after import this extension, you can use it like this:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
// Detect if an Emoji is in the string "text"
if(text.isIncludingEmoji) {
// Show an UIAlertView, or whatever you want here
return NO;
}
return YES;
}
Hope that helps ;)
Emoji characters length is 2 and so check if string length is 2 in method that is shouldChangeTextInRange: that is called after each key on keyboard hit
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
// Detect if an Emoji is in the string "text"
if([text length]==2) {
// Show an UIAlertView, or whatever you want here
return YES;
}
else
{
return NO;
}
}
Well you can detect whether it only has ascii characters using this:
[myString canBeConvertedToEncoding:NSASCIIStringEncoding];
It will say no if it fails (or has emoji). Then you can do a if else statement that does not allow them to click enter or something.
The following are cleaner and more efficient implementations of the code that checks to see if the drawn character has any color or not.
These have been written as category/extension methods to make them easier to use.
Objective-C:
NSString+Emoji.h:
#import <Foundation/Foundation.h>
@interface NSString (Emoji)
- (BOOL)hasColor;
@end
NSString+Emoji.m:
#import "NSString+Emoji.h"
#import <UIKit/UIKit.h>
@implementation NSString (Emoji)
- (BOOL)hasColor {
UILabel *characterRender = [[UILabel alloc] initWithFrame:CGRectZero];
characterRender.text = self;
characterRender.textColor = UIColor.blackColor;
characterRender.backgroundColor = UIColor.blackColor;//needed to remove subpixel rendering colors
[characterRender sizeToFit];
CGRect rect = characterRender.bounds;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 1);
CGContextRef contextSnap = UIGraphicsGetCurrentContext();
[characterRender.layer renderInContext:contextSnap];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRef imageRef = capturedImage.CGImage;
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t bytesPerPixel = 4;
size_t bitsPerComponent = 8;
size_t bytesPerRow = bytesPerPixel * width;
size_t size = height * width * bytesPerPixel;
unsigned char *rawData = (unsigned char *)calloc(size, sizeof(unsigned char));
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
BOOL result = NO;
for (size_t offset = 0; offset < size; offset += bytesPerPixel) {
unsigned char r = rawData[offset];
unsigned char g = rawData[offset+1];
unsigned char b = rawData[offset+2];
if (r || g || b) {
result = YES;
break;
}
}
free(rawData);
return result;
}
@end
Example usage:
if ([@"