Adding outline/stroke to UITextView
Asked Answered
H

3

7

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?

Herwig answered 10/1, 2013 at 2:57 Comment(4)
What's going wrong? What is your question?Humectant
I don't understand the question either. How about you just place some shadowing on the text??Loveridge
Sorry, updated the original question to be clearer.Herwig
@ttarules, I need to add outline to each character that is typed not to the entire text. thanks for the suggestion though!Herwig
N
2
// 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];
}
Nucleonics answered 6/4, 2015 at 5:57 Comment(1)
Could you please edit your answer to give an explanation of why this code answers the question? Code-only answers are discouraged, because they don't teach the solution.Gallenz
K
0

Just make a string with CSS

NSString *htmlstring = [[NSString alloc] initWithFormat:@"<html><font style=\"text-shadow: 0 0 0.2em #F87, 0 0 0.2em #F87\">%@</font></html>", YourTextView.text, nil];

^That will make whatever text is in the TextView glow read on a webpage. (You can also give it a black background if you'd like... use this:

NSString *htmlstring = [[NSString alloc] initWithFormat:@"<html><body bgcolor=\"#000000\"><font style=\"text-shadow: 0 0 0.2em #F87, 0 0 0.2em #F87\">%@</font></body></html>", YourTextView.text, nil];

Now save it as an html file and load it into a UIWebView. Or inject it into a URL via javascript and load that URL into a UIWebView.

Set the UIWebView frame and location to match that of your UITextView so that it will go ontop of it and the red-glowing text with the black background will be displayed.

Kermanshah answered 10/1, 2013 at 4:12 Comment(6)
Thanks Albert, but I want to update the UITextView in "realtime" as the user is typing. Seems like your solution would require me to place the UIWebView after the user is done editing?Herwig
You could have the UIWebView disabled so users could click through it and they could begin typing and it would update automatically (because there is practically no loading time because the html file is stored locally so you don't need WiFi or anything to retrieve it) you could add a blinking blue line at the end to simulate that the UIWebView is a UITextView and it would look very realistic, then the WebView could be updated realtime. The only set back would be trying to move the cursor back to a previous part of your text or trying to select text to copy/paste.. that wouldn't work /:Kermanshah
If you could somehow make the text on a UITextView transparent you could put the text view on top and then users would still see the blinking blue line for the cursors current location and users could edit freely just as if it were a real textview even though they are seeing a UIWebView.Kermanshah
OH!!!! Or just make a UITextView using html and they will edit the web page... you can pass the variables through via javascript! Then it will be just like editing a UITextView but they will be editing a TextArea on a fake website within your app that has red glowing text!Kermanshah
^Surely that's the best solution of my 3. Good luck! God bless!Kermanshah
Added a new answer that will work! Test it :) It's above this answer. Good luck!Kermanshah
K
0

Make an HTML file that has red glowing text in an editable textfield (TextArea).

Set the background of all elements to be transparent.

Make it into a string and load it into a UIWebView that is ontop of the image you want to put the text on.

Load the HTML string into the UIWebView and also make the UIWebView itself transparent.

*Also you might need to make your UIWebView a property and synthesize it.

Here's the code (without the synthesizing and property)

.h:

@interface ViewController : UIViewController <uiwebviewdelegate></uiwebviewdelegate> {
    IBOutlet UIWebView *webView;
    //... other objects you already have can go here too..
}

.m:

self.webView.delegate = self;
NSString *htmlstring = [[NSString alloc] initWithFormat:@"<html><body style='background-color: transparent;'><textarea name='myTextArea'cols='20' rows='10' style='text-shadow: 0 0 0.2em #F87, 0 0 0.2em #F87; background-color:transparent; border:none'>You Can Edit This Text.</textarea></body></html>"];
[self.webView loadHTMLString:htmlstring baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
self.webView.opaque = NO;
self.webView.backgroundColor = [UIColor clearColor];

Edit: Here is the code for the property and synthesize of the "webView"

@property(nonatomic,retain)IBOutlet UIWebView *nubrowser; //put in .h file at end of "@Interface" function after the closing curly bracket ("}")

@synthesize webView; //put in .m file directly after "@implementation" function
Kermanshah answered 10/1, 2013 at 18:12 Comment(5)
Change the font size and glow color and everything in the innerHTML of htmlstring. Don't forget to synthesize your UIWebView and make it a property if you plan on using it with other things.Kermanshah
*Note, if you want the html TextArea to scroll like a UITextView does you will have to add a CSS property, I can't recall it at the moment but it is fairly simple to find on google... it's like overflow:touch-scroll or something like that.Kermanshah
^You won't need this, this is just for other people in the future who want to use this method for something other than putting text over a photo...Kermanshah
**Note 2: to retrieve the text from the html's TextArea pass the variables from "innerHTML.myTextArea" via Javascript (This to can be googled easily if you aren't sure how to do it)Kermanshah
***Note 3: You might not need to use "self.webView" if you defined the webView in your viewController .h just use "webView" not "self.webView"Kermanshah

© 2022 - 2024 — McMap. All rights reserved.