2012-09-28 9 views
5

Próbuję zaimplementować własną klawiaturę zawierającą emotikony. W tym celu wstawiam emoji w pozycji kursora.uitextfield positionFromPosition: offset nie działa emoja

Działa to dobrze, jeśli w UITextField nie ma 4-bajtowych znaków emoji. W przeciwnym razie aplikacja ulega awarii.

Zamieszczam tutaj kod wstawiania. Czy ktoś może wskazać, jak rozwiązać problem?

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]; 

linia ta zwraca nil jeśli istnieją emotikony w tekście:

UITextPosition *newPos = [field positionFromPosition:field.beginningOfDocument offset:pos + 1]; 
+0

Dziękujemy! To jest taki niszowy problem, ale to mnie denerwowało. –

Odpowiedz

4

Pod koniec I rozwiązać ten pisząc własną długość i offset metody obliczeniowe, które liczą znaków 4-bajtowych jako 1 znak nie dwa.

@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 

zobaczyć pełny wpis na blogu http://bit.ly/PT9VSz

2

Znalazłem inny sposób, to działa na mnie:

- (NSRange)findRealRangeForString:(NSString *)text range:(NSRange)range 
{ 
    __block int loc = 0; 
    __block int len = 0; 
    [text enumerateSubstringsInRange:NSMakeRange(0, text.length) options:(NSStringEnumerationByComposedCharacterSequences) usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) 
    { 
     if (substringRange.location < range.location) 
      loc++; 
     else if (substringRange.location < range.location + range.length) 
      len++; 
     else 
      *stop = YES; 
    }]; 
    return NSMakeRange(loc, len); 
} 
+0

Należy zauważyć, że tekst jest pełnym tekstem, a ten zakres jest zakresem tekstu, w którym ma znaleźć prawdziwy zakres. –

+1

@AlexBeals na pewno. Wygląda na to, że moja nazwa funkcji nie jest zbyt jasna. Dzięki za opis. Funkcja próbuje skorygować podany zakres łańcucha znaków, aby nie dzielić symboli wieloliterowych. – k06a