Menu Menu
Shadows on iOS elements and performance issues

Shadows on iOS elements and performance issues

Setting shadows on the iOS UI elements can be done very easy. There are few properties in layer support of UI elements which can be used. For example, if we have a UI button named 'actionButtton', which should have a shadow, code for shadow setting will look like:

actionButton.layer.shadowOffset = CGSizeMake(5, 10);
actionButton.layer.shadowRadius = 5;
actionButton.layer.shadowOpacity = 0.5;
[actionButton.layer setShadowColor:[UIColor blackColor].CGColor];

From example above we can see that there are a few properties for shadow setup:

  1. shadowRadius, which is used to specify shadow corner radius. If we want to have rounded shadow corners we will put higher value for this parameter.
  2. shadowOpacity, which is used to specify transparency of shadow. Higher value will result in less transparent shadow.
  3. shadowOffset, which is used to specify shadow width and height.

(Picture 1, shadowRadius - 0, shadowOpacity - 0.3, shadowOffset - (2, 2))

(Picture 2, shadowRadius - 2.0, shadowOpacity - 0.9, shadowOffset - (5, 10))

By default, shadow will be shown on the right side of the element and at the bottom of it (So it's a classical dropdown shadow). In most cases code snippet from above would be enough to do the job we want, but there are some performance issues which can occur if UI element with the shadow is doing some moving on the screen. This issue is particularly experienced on iOS 5 and iOS 6. For example if we have simple panel which is taking 40% of our screen (it's custom) and we have specified logic for its movement and animation, it's highly possible that its movement will be rendered with some scrolling jumps and short time delays between two animation steps. Cause for this problem is shadow drawing pattern, actually absence of it. For this situation we have to specify exact path on which shadow will be drawn. This way, iOS will precisely now were to put the shadow and it will do rendering much faster during any movement actions or animations.

To specify shadow path, use Bezier curves to do this. Following code is setting light drop down shadow on any supplied UIView. It uses Bezier path to optimize shadow drawing.

+ (void)setLightDropShadowOn:(UIView *)view
{
    if (view)
    {
        [view.layer setShadowColor:[UIColor blackColor].CGColor];
        [view.layer setShadowOpacity:0.3];
        [view.layer setShadowRadius:1.2];
        UIBezierPath *selfBezierPath =
        [UIBezierPath bezierPathWithRoundedRect:CGRectMake(1, 4,
        view.frame.size.width + 2, view.frame.size.height + 4) cornerRadius:3.0];
        [view.layer setShadowPath:selfBezierPath.CGPath];
    }
}

In this example we are using prepared Bezier path template. If we want to draw more complex shadows, there is a support for that also. For example:

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0.0, 0.0)];
[path addLineToPoint:CGPointMake(1.0, 0.0)];
………
[path closePath];
view.layer.shadowPath = path.CGPath;

Therefore, as a conclusion, developer should always specify exact shadow location to avoid performance issues. Everything mentioned in this blog, also can be performed by second approach, by overriding drawRect method of UI view and by using Core Graphics library support inside of it.

Latest blog posts
String concatenation in Java
How we have learned a valuable lesson about teamwork
Team Boost Sessions: Wake up and boost your knowledge
Quality as one of the values we believe in
iOS Architecture Workshop: Impressions and Thoughts