Nuker
Nuker

Reputation: 2597

UITextView, NSAttributedString and custom attributes

I have searched a lot on Stack Overflow but I couldn't find a solution. Perhaps I just misinterpreted some answers.

I have created a UITextView and I am using NSAttributedStrings to work with the UITextView which is just fine.

Now, after adding a custom attribute, I am stuck.

Where can I hook in to render my custom attribute within the UITextView? Is there a delegate method, or will I have to create my own UITextView and overwrite a method?

Upvotes: 4

Views: 3116

Answers (3)

tomfriwel
tomfriwel

Reputation: 2635

You can custom NSLayoutManager, and implement it's -drawGlyphsForGlyphRange:atPoint: method.

For example, you want a custom background with a corner radius

textView init:

NSTextStorage *textStorage = [NSTextStorage new];
CustomLayoutManager *layoutManager = [[CustomLayoutManager alloc] init];
CGSize containerSize = CGSizeMake(self.view.bounds.size.width,  CGFLOAT_MAX);
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:containerSize];

textContainer.widthTracksTextView = YES;
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];

self.textView = [[UITextView alloc] initWithFrame:yourFrame textContainer:textContainer];

And apply your custom attribute:

NSMutableAttributedString *mAttrStr = [[NSMutableAttributedString alloc] initWithString:@"SampleText"];
[mAttrStr addAttribute:YourCustomAttributeName value:[UIColor redColor] range:NSMakeRange(0, mAttrStr.length)];  //for example, you want a custom background with a corner radius
[self.textView.textStorage appendAttributedString:mAttrStr];

In CustomLayoutManager.m

-(void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin {
    NSRange range = [self characterRangeForGlyphRange:glyphsToShow
                                 actualGlyphRange:NULL];
    //enumerate custom attribute in the range
    [self.textStorage enumerateAttribute:YourCustomAttributeName inRange:range options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(id  _Nullable value, NSRange range, BOOL * _Nonnull stop) {
        if (value) {
            UIColor *color = value; //the color set above

            NSRange glyphRange = [self glyphRangeForCharacterRange:range
                                          actualCharacterRange:NULL];
            NSTextContainer *container = [self textContainerForGlyphAtIndex:glyphRange.location
                                        effectiveRange:NULL];

            //draw background
            CGContextRef context = UIGraphicsGetCurrentContext();
            CGContextSaveGState(context);
            CGContextTranslateCTM(context, origin.x, origin.y);
            [color setFill];
            CGRect rect = [self boundingRectForGlyphRange:glyphRange inTextContainer:container];

            //UIBezierPath with rounded
            UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:100];
            [path fill];
            CGContextRestoreGState(context);
            //end draw

            [super drawGlyphsForGlyphRange:range atPoint:origin];
        }
        else {
            [super drawGlyphsForGlyphRange:range atPoint:origin];
        }

    }];
}

Now the 'SampleText' has a red rounded background.

Upvotes: 8

Ketan Parmar
Ketan Parmar

Reputation: 27448

If you want apply particular attributes for particular textView rather then string then you should subclass UITextView and make custom initmethod or some method that return UITextView object with specified attribute!! You can pass custom attributes as parameter in method also if attributes are change i mean not fix. and if attribute will remain same implicitly then set attributes in that class by default.

Upvotes: -1

nishith Singh
nishith Singh

Reputation: 2998

Please refer this simple code snippet to set attributed string to a textview

    let attributedString = NSMutableAttributedString(string:"Test string to add attributes")
    attributedString.addAttributes([NSForegroundColorAttributeName:UIColor.greenColor()], range: NSMakeRange(0, attributedString.string.characters.count))
    textView.attributedText = attributedString

For Objective-C

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:@"Test string to add attributes"];
[attributedString addAttributes:@{NSForegroundColorAttributeName:[UIColor greenColor]} range:NSMakeRange(0, attributedString.string.length)];
textView.attributedText = attributedString;

Hope this helps.

Upvotes: -1

Related Questions