Question

I'm writing an app that deals with rich text editing using a UITextView. It uses NSTextStorage to set new attributes for parts of the string. However, in the case that the user wants to change the font or font size at the end of the string for a new style of text or in the middle of the string (in other words when range passed to setAttributes:range: has a length of 0) this can't be done because you can't set attributes with a range of 0. So basically, how can I set a new UIFont for the position of the cursor in a UITextView?

relevant code from my NSTextStorage subclass:

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
{
NSLog(@"setAttributes:%@ range:%@", attrs, NSStringFromRange(range));

[self beginEditing];
[_backingStore setAttributes:attrs range:range];

[_backingStore fixAttributesInRange:range];

[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
[self endEditing];
}
Was it helpful?

Solution 2

Fixed it! What I ended up doing was adding an instance variable tempAttributes to my NSTextStorage subclass. If I tried to set the attributes of a string with range 0, I set tempAttributes to the attributes being passed in. Then on the next pass of the method, if tempAttributes had data, I set the range it was trying to change with that instead of the old attributes. New code:

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
{
    NSLog(@"setAttributes:%@ range:%@", attrs, NSStringFromRange(range));

[self beginEditing];
if (range.location == _backingStore.length || range.length == 0) {
    tempAttributes = attrs;
} else {
    if (tempAttributes) {
        [_backingStore setAttributes:tempAttributes range:range];
        tempAttributes = nil;
    } else {
        [_backingStore setAttributes:attrs range:range];
    }
}

[_backingStore fixAttributesInRange:range];

[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
[self endEditing];
}

OTHER TIPS

The right way to do this is to set the typingAttributes property of the UITextView.

I did in much better way. I just call [myTextView insertText: @" "] which adds a space into the text storage and range.length isn't == 0 anymore. Then I do whatever I need with that range of text. And after that I immediately call [myTextView deleteBackward: nil]. You couldn't see anything even if you're Superman, but that trick will do whatever you need with empty range.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top