Swift Swift: How to Make a Drop Shadow in User Interfaces

2015-05-18_07-50-06

Flat User interfaces are a lie. They are not completely flat. One effect continues to be used with them to show depth: Shadows. In flat interfaces it can look like there are some views floating above others by the use of shadows. In this lesson we’ll learn to make shadows using the CALayer found in UIViews, and use them to make some special effects on UIButtons.

Make a new single-view project named SwiftShadowDemo with a Swift as the Language and Universal device. Go to the storyboard.  Drag a button on to the storyboard. Give it a Blue color for a background and white lettering.  Title it Shadow.

2015-05-15_07-28-32

With the button selected, Control-Drag Up from the button and to the left, until your cursor is on the white of the background scene. Release the button. You will get a menu. Shift select the items  Center Horizontally to Container, Center vertically to Container, Equal Widths and Equal Heights like this:

2015-05-15_07-31-29

You’ve probably not set the button in the exact center of the scene.  Go to the the size inspector and find the constraints. Select Edit on the  Align X to Shadow constraint. Change the constant to 0 .

2015-05-15_07-34-46

Do the same for the Align Center Y to Shadow. When done both constraints should read like this

2015-05-15_07-35-28

Now edit the Equal Width to Superview. Change the multiplier to 3 or 1:3 depending which gives you a smaller rectangle.

 2015-05-15_07-36-09

Do the same to Equal Height to Superview, with a multiplier of 3 or 1:3.  Next in the resolver menu, Update the frames

2015-05-15_07-37-16

This should give you a centered proportionally sized button:

2015-05-15_07-37-51

Open the assistant editor. Control-drag from the button to the code. Make an outlet named shadowButton.


 @IBOutlet weak var shadowButton: UIButton!

 

Control drag again from the button to the code. Make a action named shadowButton.

@IBAction func shadowButton(sender: AnyObject) {
}

Making Shadows on the CALayer

All UIViews have a special property layer of type CALayer. This is a Core Animation layer. As it name implies various animation effects to your views happen here.  The layer property is great for many quick special effects, some built-in. Drop shadows are one of those built-in effects.  Add the following to viewDidLoad.

shadowButton.layer.shadowOpacity = 0.7

The property shadowOpacity defaults to 0.  The shadow is always there, but hidden. To show a shadow, change the opacity. Build and run. We have a shadow:

2015-05-17_06-42-06

This shadow’s light source is from the lower right. Most times it’s best to have a light source from the top and left, so the shadow shows on the lower right. We change that by the  property of CALayer. Add this to viewDidLoad:

shadowButton.layer.shadowOffset = CGSize(width: 10.0, height: 10.0)

Build and run and you get this:

2015-05-17_06-52-19

We have  a nice bold shadow.  Usually shadows are subtle. Change the shadowOffset to this:

shadowButton.layer.shadowOffset = CGSize(width: 3.0, height: 2.0)

Build and run. The shadow is more subtle:

2015-05-17_12-18-32

We can also change the radius of the shadow. This affects how blurry the shadow appears.  Add this to viewDidLoad

shadowButton.layer.shadowRadius = 5.0

Build and run:

2015-05-17_12-25-10

We have a more blurred shadow.  We can also change the color of the shadow.  The default color is black. Let’s change the color to yellow.  Add this:

shadowButton.layer.shadowColor = UIColor.yellowColor().CGColor

Build and run. Rhe shadow now look like more of a glow.

2015-05-18_05-36-45

Glows are more radiant from the center. For a good glow effect change the code to the following:

shadowButton.layer.shadowOpacity = 0.7
shadowButton.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
shadowButton.layer.shadowRadius = 15.0
shadowButton.layer.shadowColor = UIColor.yellowColor().CGColor
view.backgroundColor = UIColor.grayColor()

To better see the glow we made the background gray to contrast against the glow.  Build and run:

2015-05-18_06-11-03

We get a glow behind the button.

While this is nice for a static shadow, glows and shadows make for dynamic effects on a button.  To the shadow button action, add the following code:

 @IBAction func shadowButton(sender: AnyObject) {
     shadowButton.layer.shadowOpacity = 0.7
     shadowButton.layer.shadowOffset = CGSize(width: 3.0, height: 2.0)
     shadowButton.layer.shadowRadius = 5.0
     shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
}

This will make our simple drop shadow when we release the button. When we press the button, we will give one of two shadow effects, depending on the selection on a segmented control.  Add this outlet and action to your code:

 @IBOutlet weak var touchDownType: UISegmentedControl!
@IBAction func shadowButtonTouchDown (sender: AnyObject) {
// code to change the button on pressing
    if touchDownType.selectedSegmentIndex == 0{ //make the button glow
         shadowButton.layer.shadowOpacity = 0.5
         shadowButton.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
         shadowButton.layer.shadowColor = UIColor.yellowColor().CGColor
         shadowButton.layer.shadowRadius = 20.0
    } else { //make the button depress by having a shadow in the upper left
         shadowButton.layer.shadowOpacity = 0.9
         shadowButton.layer.shadowOffset = CGSize(width: -3.0, height: -2.0)
         shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
         shadowButton.layer.shadowRadius = 2.0
    }
}

Go to the storyboard. Add a segmented control above the button. Control drag directly down from the segmented control to the button. In the auto layout menu that appears, Shift-select Vertical Spacing, Center X,  and Equal Widths

2015-05-18_06-28-31

As we did earlier with the button, we will change some constraints. With the segmented control selected, go to the size inspector.  Change the Bottom Space to Shadow  constraint to 20. Change Align Center X to Shadow to 0. Your constraints should read like this:

2015-05-19_05-33-50

Change the first segment title to Glow. Change the second segment title to Depression. Select the button. In the size inspector, change the Proportional width to Superview’s Multiplier to 1.5 if set it at 3. Set the multiplier to  1:1.5 if set at 1:3.

2015-05-18_06-38-29

Your scene should look like this:

2015-05-18_06-39-41

Open the assistant editor. From the circle next to the touchDownType outlet, drag to the storyboard to connect it to the segment.

2015-05-18_06-55-09

For events other than a touch up for a button we need to explicitly set the event. For our new action, we need to set an event for touching down on the button. Right click the button in the storyboard. In the menu that appears, find Touch Down. Drag from the circle to the right up to anywhere in the shadowButtonTouchDown  method’s code in the assistant editor. When the code highlights, release the button.

2015-05-18_06-59-05

We have wired our storyboard up. Now to set our default. Change viewDidLoad to this:

override func viewDidLoad() {
super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    shadowButton.layer.shadowOpacity = 0.5
    shadowButton.layer.shadowOffset = CGSize(width: 3.0, height: 2.0)
    shadowButton.layer.shadowRadius = 5.0
    shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
    shadowButton.setTitleColor(UIColor.yellowColor(), forState: .Highlighted) //need to show button title
    view.backgroundColor = UIColor(red: 0.25, green: 0.2, blue: 0.6, alpha: 1.0)
}

We set up our basic shadow, like we did in the touch up event. We also added two lines of code to makes things a bit more visible. First we changed the color of the button’s title. If we leave it as the white from the storyboard, it will disappear. Changing the color to yellow fixes this. Secondly, we gave a contrasting color to both our glow and shadow so they are visible.

Build and run. Rotate the device in the simulator with Command-Right arrow. You should see this:

   2015-05-18_07-21-47

Press the button, and the button should glow:

2015-05-18_07-22-14

Switch to Depression

2015-05-18_07-23-04

Press the button and the button seems to press down:

2015-05-18_07-23-28

This is some of the basics of drop shadows. You can do this to any UIView based control.  For example you can do this to the segment and a label, which we’ll leave to the reader to set up to produce the image below:


//a shadow on the segmented control and on a label
//label layout and setup is left to the reader.
let offset = CGSize(width: 3.0, height: 2.0) //keep offsets consistent -- usually make this a constant.
touchDownType.layer.shadowOpacity = 0.7
touchDownType.layer.shadowOffset =  offset
shadowLabel.layer.shadowOffset = offset
shadowLabel.layer.shadowOpacity = 0.9
shadowLabel.layer.shadowRadius = 7.0

2015-05-18_07-50-06

The Whole Code

//
//  ViewController.swift
//  SwiftShadowDemo
//
//  Created by Steven Lipton on 5/15/15.
//  Copyright (c) 2015 MakeAppPie.Com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
//MAARK: - Outlets
    @IBOutlet weak var shadowLabel: UILabel!
    @IBOutlet weak var shadowButton: UIButton!
    @IBOutlet weak var touchDownType: UISegmentedControl!
//MARK: - Actions
    @IBAction func shadowButtonTouchDown (sender: AnyObject) { //When button is pressed down
        if touchDownType.selectedSegmentIndex == 0{
            shadowButton.layer.shadowOpacity = 0.5
            shadowButton.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
            shadowButton.layer.shadowColor = UIColor.yellowColor().CGColor
            shadowButton.layer.shadowRadius = 20.0
        } else {
            shadowButton.layer.shadowOpacity = 0.9
            shadowButton.layer.shadowOffset = CGSize(width: -3.0, height: -2.0)
            shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
            shadowButton.layer.shadowRadius = 2.0
        }
    }

    @IBAction func shadowButton(sender: AnyObject) { //When button released
        shadowButton.layer.shadowOpacity = 0.5
        shadowButton.layer.shadowOffset = CGSize(width: 3.0, height: 2.0)
        shadowButton.layer.shadowRadius = 5.0
        shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
    }
//MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        shadowButton.layer.shadowOpacity = 0.5
        shadowButton.layer.shadowOffset = CGSize(width: 3.0, height: 2.0)
        shadowButton.layer.shadowRadius = 5.0
        shadowButton.layer.shadowColor = UIColor.blackColor().CGColor
        shadowButton.setTitleColor(UIColor.yellowColor(), forState: .Highlighted) //need to show button title
        view.backgroundColor = UIColor(red: 0.25, green: 0.2, blue: 0.6, alpha: 1.0)

        //extra code not in post - a shadow on the segmented control and on a label
        let offset = CGSize(width: 3.0, height: 2.0) //keep offsets consistent -- usually make this a constant.

        touchDownType.layer.shadowOpacity = 0.7
        touchDownType.layer.shadowOffset =  offset
        shadowLabel.layer.shadowOffset = offset
        shadowLabel.layer.shadowOpacity = 0.9
        shadowLabel.layer.shadowRadius = 7.0

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s