CALayer Tutorial for iOS: Getting Started
In this article, you’ll learn about CALayer and how it works. You’ll use CALayer for cool effects like shapes, gradients and particle systems. By Ron Kliffer.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
CALayer Tutorial for iOS: Getting Started
35 mins
- Getting Started
- How does CALayer relate to UIView?
- Customizing Views With CALayer
- Improving Performance With ShouldRasterize and DrawsAsynchronously
- Scrolling With CAScrollLayer
- Setting up Scrolling
- Locking Scrolling Directions
- Rendering Text With CATextLayer
- Playing Media With AVPlayerLayer
- Setting up Media Playback
- Changing Playback Speeds
- Updating the User Interface
- Resetting the Playback Cursor
- Color Blending With CAGradientLayer
- Creating a Loading Animation with CAReplicatorLayer
- Configuring Replicator Layers
- Setting Position and Fade
- Drawing a Star With CAShapeLayer
- Drawing a 3D Cube With CATransformLayer
- Rotating the Cube
- Making a Shooting Star With CAEmitterLayer
- Preparing the Emitter Layer
- Setting up the Emitter Cell
- Where to Go From Here?
Locking Scrolling Directions
Add the following code to scrollingSwitchChanged(_:)
:
switch (horizontalScrollingSwitch.isOn, verticalScrollingSwitch.isOn) {
case (true, true):
scrollingViewLayer.scrollMode = .both
case (true, false):
scrollingViewLayer.scrollMode = .horizontally
case (false, true):
scrollingViewLayer.scrollMode = .vertically
default:
scrollingViewLayer.scrollMode = .none
}
Here, you add a simple switch
block. It determines the scrolling direction according to the values of the switches in the user interface.
Now build and run. Go back to the app, flip the switches and see how CAScrollLayer
behaves.
Here are some rules of thumb for when to use — or not to use — CAScrollLayer
:
- If you want something lightweight and you only need to scroll programmatically, consider using
CAScrollLayer
. - When you want the user to be able to scroll, you’re better off with
UIScrollView
. To learn more, check out our Scroll View School video tutorial series. - If you’re scrolling a very large image, consider using
CATiledLayer
.
Rendering Text With CATextLayer
CATextLayer
provides simple but fast rendering of plain text or attributed strings. Unlike UILabel
, a CATextLayer
cannot have an assigned UIFont
, only a CTFont
or CGFont
.
Open CATextLayerViewController.swift and add the following to the end of setUpTextLayer()
:
// 1
textLayer.font = helveticaFont
textLayer.fontSize = Constants.baseFontSize
// 2
textLayer.foregroundColor = UIColor.darkGray.cgColor
textLayer.isWrapped = true
textLayer.alignmentMode = .left
textLayer.truncationMode = .end
// 3
textLayer.contentsScale = UIScreen.main.scale
Here’s what you’re doing:
- You set the font of the text layer. Notice that this is a
CTFont
and not aUIFont
. You create these usingCTFontCreateWithName(_:_:_:)
.CATextLayer
lets you set the font size directly on the layer, as you do here. - Next, you set the text color, wrapping, alignment and truncation modes. All of these are also available on a regular
UILabel
orUITextView
. - Finally, you set the layer’s
contentsScale
to match the screen’s scale. All layer classes, not justCATextLayer
, render at a scale factor of 1 by default. Attaching a layer to a view automatically sets itscontentsScale
to the appropriate scale factor for the current screen. For any layer you create manually, however, you must setcontentsScale
explicitly. Otherwise, its scale factor will be 1, causing it to appear pixelated on Retina displays.
Build and run, then select CATextLayer from the menu. Layer Player has controls to change many of CATextLayer
‘s properties. Play around with them to see what they do:
Next, you’ll give Layer Player the ability to play media files.
Playing Media With AVPlayerLayer
AVPlayerLayer
adds a sweet layer of goodness to AVFoundation
. It holds an AVPlayer
to play media files of type AVPlayerItem
.
Setting up Media Playback
Open AVPlayerLayerViewController.swift and add the following code to setUpPlayerLayer()
:
// 1
playerLayer.frame = viewForPlayerLayer.bounds
// 2
let url = Bundle.main.url(forResource: "colorfulStreak", withExtension: "m4v")!
let item = AVPlayerItem(asset: AVAsset(url: url))
let player = AVPlayer(playerItem: item)
// 3
player.actionAtItemEnd = .none
// 4
player.volume = 1.0
player.rate = 1.0
playerLayer.player = player
In this code, you set up the player. Here’s how:
- First, you set the layer’s frame.
- Next, you create a player with an
AVPlayerItem
. - You tell the player to do nothing when it finishes playing. Additional options include pausing or advancing to the next asset, if applicable.
- Finally, you set the volume and rate of the player.
Now that you can play media files, you’re going to give your users the ability to change the speed at which they play.
Changing Playback Speeds
rate
sets the video playing speed. 0 means pause and 1 means the video plays at regular speed.
However, setting rate
also instructs playback to commence at that rate. In other words, calling pause()
and setting rate
to 0 does the same thing, as does calling play()
and setting rate
to 1!
So what about fast forward, slow motion or playing in reverse? Well, AVPlayer
has you covered!
When you set rate
to anything higher than 1, playback commences at that number times the regular speed. For instance, setting rate
to 2 means double speed. And setting rate
to a negative number results in playback at that number times regular speed in reverse.
Before playback occurs at any rate other than forward at regular speed, however, you should check the appropriate variable in AVPlayerItem
to verify that it can be played back at that rate:
-
canPlayFastForward
for any number higher than 1. -
canPlaySlowForward
for any number between 0 and up to, but not including, 1. -
canPlayReverse
for -1. -
canPlaySlowReverse
for any number between -1 and up to, but not including, 0. -
canPlayFastReverse
for any number lower than -1.
Most videos can play at various forward speeds, but it’s less common that they can play in reverse.
Updating the User Interface
Now, back to the code. When you tap the play button, it should toggle the controls to play AVAsset
and set the button’s title.
Add the following to playButtonTapped(_:)
:
if player?.rate == 0 {
player?.rate = rate
updatePlayButtonTitle(isPlaying: true)
} else {
player?.pause()
updatePlayButtonTitle(isPlaying: false)
}
Here, you toggle the player’s state and update the play button’s title, depending on the initial rate.
Finally, you’ll add code to move the playback cursor back to the beginning when the player has reached the end of the media file.
Resetting the Playback Cursor
In viewDidLoad()
, you can see that AVPlayerItemDidPlayToEndTimeNotification
has an observer. This notification is called when an AVPlayerItem
has reached the end.
Add the following code to playerDidReachEndNotificationHandler(_:)
:
// 1
guard let playerItem = notification.object as? AVPlayerItem else { return }
// 2
playerItem.seek(to: .zero, completionHandler: nil)
// 3
if player?.actionAtItemEnd == .pause {
player?.pause()
updatePlayButtonTitle(isPlaying: false)
}
In this code:
- You verify that the notification object is an
AVPlayerItem
. - You use
seek(to:completionHandler:)
to send the player to a desired position. In this case, you send the player toCMTime.zero
— which is the beginning. - You pause the player if its
actionAtItemEnd
is set to.pause
, and you set the button text accordingly.
Build and run and select AVPlayerLayer from the menu. Change the values on the controls to see how each one changes the layer’s behavior.
For your next step, you’ll see how easy it is to make cool gradients with CALayer
.