Core Graphics Tutorial: Shadows and Gloss

Make your UI elements stand out by applying shadows and gloss. Shadows create a feeling of depth, while gloss makes your elements shine. By Ehab Amer.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 2 of this article. Click here to view the first page.

Drawing Drop Shadows

Now that the rectangles are clearly defined, add the shadow. In CustomHeader.swift, add these two variables after coloredBoxHeight:

var lightColor = UIColor(red: 105/255.0, green: 179/255.0, blue: 216/255.0, alpha: 1)
var darkColor = UIColor(red: 21/255.0, green: 92/255.0, blue: 136/255.0, alpha: 1)

Next, in draw(_:) method remove the following four lines from the bottom of the method.

context.setFillColor(UIColor.red.cgColor)
context.fill(coloredBoxRect)
    
context.setFillColor(UIColor.green.cgColor)
context.fill(paperRect)

Then add these lines instead:

// 1:
let shadowColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.5)
// 2:
context.saveGState()  
// 3:
context.setShadow(
  offset: CGSize(width: 0, height: 2), 
  blur: 3.0,
  color: shadowColor.cgColor) 
// 4:
context.setFillColor(lightColor.cgColor)
context.fill(coloredBoxRect) 
// 5:
context.restoreGState()

That’s how you draw a shadow! Here’s what the above code means, step by step:

  1. Define the shadow as a gray color with 50% transparency.
  2. Save the current graphics state so you can apply any configuration changes you need and return back to this state when you finish.
  3. Set the shadow configuration for anything you will draw.
  4. Draw the colored box. Without this there will be no shadow applied on the screen.
  5. Return to the graphics configuration you saved above.

Finally, in CoolTableViewController.swift, at the end of tableView(_:viewForHeaderInSection:) just before the return, add the following lines:

if section == 1 {
  customHeaderView.lightColor = UIColor(
    red: 147/255.0,
    green: 105/255.0,
    blue: 216/255.0,
    alpha: 1)
  customHeaderView.darkColor = UIColor(
    red: 72/255.0,
    green: 22/255.0,
    blue: 137/255.0,
    alpha: 1)
}

This is to show a different color for the second table section. darkColor is not used yet, so don’t worry about it.

Build and run. You should see a huge improvement from last time you ran the app. The headers look better now, right? Next, you’ll add a gloss effect.

Adding a Gloss Effect

There’s more than one way to apply a gloss effect. Matt Gallagher and Michael Heyeck explained harder ways to do it, but here, you’ll learn a simple way.

For simplicity’s sake, implementing an approximation of a gloss effect by applying a gradient alpha mask is good enough approach for now.

Pro tip: this is a commonly used approach, so why not put it in a separate file for easy access in later projects? Extensions.swift is the file for that job. It has a few handy extensions that make things much easier.

At the end of the CGContext extension, add this method:

func drawGlossAndGradient(rect: CGRect, startColor: UIColor, endColor: UIColor) {
  // 1:
  drawLinearGradient(rect: rect, startColor: startColor, endColor: endColor)
  // 2:
  let glossColor1 = UIColor.white.withAlphaComponent(0.35)
  let glossColor2 = UIColor.white.withAlphaComponent(0.1)
  // 3:
  var topHalf = rect
  topHalf.size.height /= 2
  // 4:
  drawLinearGradient(rect: topHalf, startColor: glossColor1, endColor: glossColor2)
}

Here’s what the code above does:

  1. Call another method that’s in the extensions file from the sample project which draws a two-color gradient in a rectangle.
  2. Define the two white gloss colors.
  3. Calculate the rectangle that will have the white gradient, or the gloss. This rectangle is half the colored gradient area.
  4. Draw the white gradient in the smaller rectangle.

In CustomHeader.swift, at the end of draw(_:), add this line:

context.drawGlossAndGradient(
  rect: coloredBoxRect,
  startColor: lightColor,
  endColor: darkColor)

Build and run. You’ll see a nice header with a gradient color and a gloss effect.

The last thing you need is the final stroke around the colored area of the header. Right after the line you just added, add the following lines:

context.setStrokeColor(darkColor.cgColor)
context.setLineWidth(1)
context.stroke(coloredBoxRect.rectFor1PxStroke())

Build and run. Notice the darker stroke that you wanted.

Where to Go From Here?

CGContext has a lot of interesting drawing tools you can use to draw paths, lines, shapes, text, and images. It’s worth looking at the developer documentation and experimenting with it.

You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

I hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below.