2013-06-23 3 views
3

Вот моя ситуация:Добавить атрибуты NSMutableAttributedString посимвольны

Я в NSMutableAttributedString без каких-либо атрибутов в текстовом виде. Всякий раз, когда пользователь нажимает клавишу backspace, я не хочу, чтобы символ был удален, я хочу, чтобы он был пробит, как и функция «Отслеживание изменений» в наборах производительности. Я хочу, чтобы пользователь мог продолжить типизацию после этого. Вот как я начал:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 
{ 
if (text.length == 0 && textView.text.length == 0) return YES; 

if (text.length == 0 && !([[textView.text substringFromIndex:textView.text.length - 1] isEqualToString:@" "] || [[textView.text substringFromIndex:textView.text.length - 1] isEqualToString:@"\n"])) { 

    textView.attributedText = [self strikeText:textView.attributedText]; 

    textView.selectedRange = NSMakeRange(textView.attributedText.length - 1, 0); 

    return NO; 
} 
return YES; 
} 

- (NSAttributedString *)strikeText:(NSAttributedString *)text 
{ 
NSRange range; 
NSMutableAttributedString *returnValue = [[NSMutableAttributedString alloc] initWithAttributedString:text]; 

if (![text attribute:NSStrikethroughStyleAttributeName atIndex:text.length - 1 effectiveRange:&range]) { 
    NSLog(@"%@", NSStringFromRange(range)); 
    NSLog(@"%@", [text attribute:NSStrikethroughStyleAttributeName atIndex:text.length - 1 effectiveRange:&range]); 

    [returnValue addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(text.length - 1, 1)]; 
    [returnValue addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(text.length - 1, 1)]; 
} 
else { 
    [returnValue addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(range.location - 1, 1)]; 
    [returnValue addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(range.location - 1, 1)]; 
} 

[returnValue removeAttribute:NSStrikethroughStyleAttributeName range:NSMakeRange(returnValue.length, 1)]; 

return returnValue; 


} 

Однако, независимо от того, насколько сильно я думаю, я не могу обернуть мою голову вокруг ситуации. Этот код не работает или работает частично. Значение, возвращаемое attribute: atIndex: effectiveRange:, всегда равно нулю, не имеет значения, действительно ли атрибут существует или нет. Эффективный диапазон выходит за рамки текста, который у меня есть.

Пожалуйста, помогите мне здесь.

ответ

6

В вашем методе strikeText: вы проверяете только конец вашего атрибутаString. Если вы хотите проверить последний символ, вы должны проверить его с text.length -2, считая, что текст достаточно длинный. Кроме того, вы удаляете атрибут в конце метода, и это не имеет особого смысла.

простой подход о том, как вы можете использовать диапазон от уполномоченной-протокола, чтобы ударить только символы, нужно:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 
{ 
    // check if your replacement is going to be empty, therefor deleting 
    if ([text length] == 0) { 

     // don't strike spaces and newlines, could use NSCharacterSet here 
     NSString *textToDelete = [textView.text substringWithRange:range]; 
     if (![@[ @" ", @"\n" ] containsObject:textToDelete]) { 
      textView.attributedText = [self textByStrikingText:textView.attributedText inRange:range]; 
     } 

     textView.selectedRange = NSMakeRange(range.location, 0); 

     return NO; 
    } 

    return YES; 
} 

- (NSAttributedString *)textByStrikingText:(NSAttributedString *)text inRange:(NSRange)range 
{  
    NSMutableAttributedString *strickenText = [[NSMutableAttributedString alloc] initWithAttributedString:text]; 

    [strickenText addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleSingle) range:range]; 
    [strickenText addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:range]; 

    return strickenText; 
} 

Там может быть более крайние случаи, но это простой подход, который делает то, что вы хотеть.

+0

К сожалению, ваш код тоже есть проблемы. Я хочу, чтобы курсор находился в конце пробитого текста. И если я напечатаю что-нибудь еще после того, как какой-то текст был пробит, вновь вставленный текст тоже пробивается. – duci9y

+0

Я объяснил причину вашей проблемы с атрибутом: atIndex: effectiveRange: в первой части. Приведенный код не должен быть полным решением, а направлением для продолжения. – Karl

5

Вы должны попробовать:

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"Hello. That is a test"]; 
[str addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:22] range:NSMakeRange(2,1)]; 
[str addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(8,2)]; 
[str addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(18,2)]; 

И атрибуты описаны здесь: https://developer.apple.com/reference/foundation/nsattributedstring/1652619-character_attributes?language=objc