逐个字符地向NSMutableAttributedString添加属性

时间:2013-06-23 09:43:13

标签: ios nsattributedstring nsrange

这是我的情况:

我在文本视图中没有属性NSMutableAttributedString。每当用户按下退格键时,我都不希望删除一个字符,我希望它能够被删除,就像生产力套件的“Track Changes”功能一样。我希望用户能够在此之后继续正常输入。这是我开始的方式:

- (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:返回的值始终为nil,如果属性实际存在与否则无关紧要。有效范围超出了我的文本范围。

请帮帮我。

2 个答案:

答案 0 :(得分:6)

strikeText:方法中,您只检查您的attributesString的最后一部分。如果你想检查你应该从text.length -2检查的最后一个字符,假设文本足够长。另外你在方法结束时的removeAttribute对我来说也没有多大意义。

一种简单的方法,介绍如何重用代表协议中的范围来仅触发您需要的字符:

- (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;
}

可能会有更多边缘情况,但这是一种可以实现您想要的简单方法。

答案 1 :(得分: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