Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to draw text with shadows using the NSString UIKit additions?

Tags:

ios

uikit

Is it possible to draw with simple text shadows when using the NSString UIKit additions? I mean without writing code to draw twice in two colors, as can be done with various UIKit classes such as UILabel and its shadowColor and shadowOffset properties, and also without doing actual blur shadows via CGContextSetShadow (which are bound to be much more expensive).

Apple's doc for these extensions actually include constants (at the very bottom) including UITextAttributeTextShadowColor and UITextAttributeTextShadowOffset which implies that it is possible, but I don't see any possible usage of these in the actual methods.

like image 998
Clafou Avatar asked Jun 16 '13 00:06

Clafou


2 Answers

A couple of thoughts:

  1. The UITextAttributeTextShadow... keys are intended for when using a text attribute dictionary with, for example, UIAppearance methods:

    NSDictionary *attributes = @{UITextAttributeTextShadowColor  : [UIColor blackColor],
                                 UITextAttributeTextShadowOffset : [NSValue valueWithUIOffset:UIOffsetMake(2.0, 0.0)],
                                 UITextAttributeTextColor        : [UIColor yellowColor]};
    
    [[UINavigationBar appearance] setTitleTextAttributes:attributes];
    

    The UITextAttributeTextShadow... keys are designed for use only in those methods that accept a text attributes dictionary.

  2. The closest equivalent key when drawing text strings is the use of attributed strings with the NSShadowAttributeName key:

    - (void)drawRect:(CGRect)rect
    {
        UIFont *font = [UIFont systemFontOfSize:50];
    
        NSShadow *shadow = [[NSShadow alloc] init];
        shadow.shadowColor = [UIColor blackColor];
        shadow.shadowBlurRadius = 0.0;
        shadow.shadowOffset = CGSizeMake(0.0, 2.0);
    
        NSDictionary *attributes = @{NSShadowAttributeName          : shadow,
                                     NSForegroundColorAttributeName : [UIColor yellowColor],
                                     NSFontAttributeName            : font};
    
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"this has shadows" attributes:attributes];
    
        [attributedText drawInRect:rect];
    }
    

    If you're concerned about the performance hit of a shadow algorithm capable of doing a bezier curve shadow, though, NSShadow may suffer from that. But doing some benchmarks, changing the shadowBlurRadius dramatically affects performance. For example, animating the rotation of a complex multi-line text with a shadowBlurRadius of 10.0 on a slow iPhone 3GS achieved a frame rate of 31 fps, but changing shadowBlurRadius to 0.0 yielded a frame rate of 60 fps.

    Bottom line, using a shadow blur radius of 0.0 eliminates most (if not all) of the computational overhead of a bezier generated shadow.

  3. FYI, I experience a similar performance improvement by setting the blur value to 0.0 for CGContextSetShadow, just like I experienced with the attributed text rendition above.

Bottom line, I don't think you should fear the computational overhead of bezier-based shadows as long as you use a blur radius of 0.0. I wouldn't be surprised if writing the text twice yourself, once for the shadow and again for the foreground color, might even be a bit more efficient, but I'm not sure if the difference will be observable. But I don't know of any API call that will do that for you (other than CGContextSetShadow with blur of 0.0).

like image 196
Rob Avatar answered Sep 28 '22 02:09

Rob


The following snippet uses CALayer to add shadow around the edges of the characters in a UILabel:

 _helloLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
[_helloLabel setBackgroundColor:[UIColor clearColor]];
[_helloLabel setTextColor:[UIColor whiteColor]];
[_helloLabel setTextAlignment:NSTextAlignmentCenter];
[_helloLabel setFont:[UIFont lightApplicationFontOfSize:30]];

_helloLabel.layer.shadowColor = UIColorFromRGB(0xd04942).CGColor;
_helloLabel.layer.shadowOffset = CGSizeMake(0, 0);
_helloLabel.layer.shadowRadius = 2.0;
_helloLabel.layer.shadowOpacity = 1.0;

[self addSubview:_helloLabel];

. . normally this would add a shadow around the border, but UILabel seems to treat these properties as a special case.

like image 21
Jasper Blues Avatar answered Sep 28 '22 00:09

Jasper Blues