Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

uitextfield positionFromPosition:offset not working emojis

I am trying to implement my own keyboard containing emojis. For this purpose I am inserting the emoji in the cursor position.

This works fine if no 4-bytes emoji characters exist in UITextField. Otherwise the app gets crashed.

I am posting the insertion code here. Can someone point out how to solve the issue?

UITextField *field = self.textField;
UITextRange *range = field.selectedTextRange;
int pos = [field offsetFromPosition:field.beginningOfDocument toPosition:range.end];
NSString * firstHalfString = [field.text substringToIndex:pos];  
NSString * secondHalfString = [field.text substringFromIndex:pos];  
field.text = [NSString stringWithFormat: @"%@%@%@", firstHalfString, emoticon, secondHalfString];
UITextPosition *newPos = [field positionFromPosition:field.beginningOfDocument offset:pos + 1];
field.selectedTextRange = [field textRangeFromPosition:newPos toPosition:newPos];

this line returns nil if there are emojis in the text:

UITextPosition *newPos = [field positionFromPosition:field.beginningOfDocument offset:pos + 1];
like image 474
Behlül Avatar asked Sep 28 '12 20:09

Behlül


1 Answers

At the end I solved this by writing my own length and offset calculation methods which count 4-byte characters as 1 character, not two.

@implementation NSString (UnicodeAdditions)
-(NSInteger)utf32length {
    const char* bytes = [self UTF8String];
    int length = [self lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
    int newLength = 0;
    for (int i=0; i<length; i++) {
        if (((unsigned char)bytes[i] >> 7) == 0b00000000)  {
          newLength++;
        }
        else if (((unsigned char)bytes[i] >> 5) == 0b00000110) {
            newLength++;
            i+=1;
        }
        else if (((unsigned char)bytes[i] >> 4) == 0b00001110) {
            newLength++;
            i+=2;
        }
        else if (((unsigned char)bytes[i] >> 3) == 0b00011110) {
            newLength++;
            i+=3;
        }
    }
    return newLength;
}


-(NSInteger)utf32offsetWithOffset:(NSInteger)offset {
    const char* bytes = [self UTF8String];
    int length = [self lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
    int newLength = 0;
    for (int i=0; i<length && offset!=0; i++) {
        if (((unsigned char)bytes[i] >> 7) == 0b00000000)  {
            offset--;
            newLength++;
        }
        else if (((unsigned char)bytes[i] >> 5) == 0b00000110) {
            offset--;
            newLength++;
            i+=1;
        }
        else if (((unsigned char)bytes[i] >> 4) == 0b00001110) {
            offset--;
            newLength++;
            i+=2;
        }
        else if (((unsigned char)bytes[i] >> 3) == 0b00011110) {
            offset-=2;
            newLength++;
            i+=3;
        }
    }
    return newLength;
}

@end

see the full blog post http://bit.ly/PT9VSz

like image 149
Behlül Avatar answered Sep 28 '22 02:09

Behlül