Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding outline/stroke to UITextView

I want to add an outline or stroke to an editable UITextView text as the user types. Exactly like memes : http://t.qkme.me/3oi5rs.jpg

enter image description here

I have to use a UITextView since I need multi line support. I have tried all the approaches and reached the conclusion that I must use CoreText. I got almost all of the solution working but got stuck at a point where the text in textview wraps. My drawRect routine in the subview of UITextView correctly draws the outline text until the text wraps. Even when the text user inputs is wrapped, the outline text that I draw does not. Here's my implementation of the drawRect method : https://gist.github.com/4498988. On line 29, I am using char wrapping :

CTLineBreakMode linebreakmode = kCTLineBreakByCharWrapping;

I have already tried the wordwrapping option (which is also the default) to no use.

My question is : How do I get the text that I draw to wrap correctly so it appears as an outline to the typed text?

like image 733
trunal bhanse Avatar asked Jan 10 '13 02:01

trunal bhanse


1 Answers

// make your UITextView as a subclass of UITextView
// and override -drawRect: method in your UITextView subclass 
- (void)drawRect:(CGRect)rect
{
    self.textColor = [UIColor clearColor];

    [self setTypingAttributes:[NSDictionary dictionaryWithObjectsAndKeys:self.font, NSFontAttributeName, _textBaseColor, NSForegroundColorAttributeName, nil ]]; // _textBaseColor is any color of your choice
    CGRect newRect = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetTextDrawingMode(context, kCGTextStroke);
    // Make the thickness of the outline shadow. and increase the y position of shadow rect by 2.
    CGContextSetLineWidth(context, (TEXTOUTLINE_PERCENT/100 * self.font.pointSize)+1); // TEXTOUTLINE_PERCENT can be 25.
    CGContextSetLineJoin(context, kCGLineJoinRound);
    CGContextSetLineCap(context, kCGLineCapButt);
    CGContextSetStrokeColorWithColor(context, [UIColor clearColor].CGColor);
    CGRect shadowrect = newRect;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        shadowrect.origin.y += 0.5;
    }
    else
    {
        shadowrect.origin.y += 2;
    }

    [self.text drawInRect:shadowrect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:self.font, NSFontAttributeName, SHADOW_COLOR , NSForegroundColorAttributeName, nil]]; // SHADOW_COLOR can be [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.3]

    // Make the thickness of the outline border of the text.
    CGContextSetLineWidth(context, TEXTOUTLINE_PERCENT/100 * self.font.pointSize); // TEXTOUTLINE_PERCENT can be 25.
    CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
    [self.text drawInRect:newRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:self.font, NSFontAttributeName, self.textOutlineColor , NSForegroundColorAttributeName,  nil]];

    // Draw filled text. This is the actual text.
    CGContextSetTextDrawingMode(context, kCGTextFill);
    CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
    [self.text drawInRect:newRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:self.font, NSFontAttributeName, _textBaseColor, NSForegroundColorAttributeName,_textBaseColor, NSStrokeColorAttributeName, nil]];
    [super drawRect:rect];
}
like image 63
govind sah Avatar answered Nov 11 '22 09:11

govind sah