Modern iOS applications often need to switch video content between portrait and landscape modes. Whether you are building a media player, a streaming application, or a custom video interface, understanding how to rotate views and video layers smoothly is essential for creating a professional user experience.
This article explains how to animate the rotation of a UIView or an AVPlayerLayer by 90 degrees in Swift 5.
Understanding View Rotation in iOS
In iOS, rotation is typically performed using either:
CGAffineTransformCATransform3D- Core Animation (
CABasicAnimation)
The most common approach for rotating a UIView is using CGAffineTransform.
Rotating a UIView by 90 Degrees
The following example rotates a view 90 degrees clockwise:
UIView.animate(withDuration: 0.5) {
self.playerContainer.transform = CGAffineTransform(rotationAngle: .pi / 2)
}
Explanation
.pi / 2= 90 degrees.pi= 180 degrees-.pi / 2= -90 degrees
Rotating Back to Portrait
To return the view to its original position:
UIView.animate(withDuration: 0.5) {
self.playerContainer.transform = .identity
}
The .identity transform resets all transformations.
Rotating an AVPlayerLayer
An AVPlayerLayer is a Core Animation layer rather than a view. Therefore, you must use a layer transformation.
Immediate Rotation
var transform = CATransform3DIdentity
transform = CATransform3DRotate(transform, .pi / 2, 0, 0, 1)
playerLayer.transform = transform
This rotates the video layer 90 degrees around the Z-axis.
Animating AVPlayerLayer Rotation
To animate the rotation smoothly:
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.fromValue = 0
rotationAnimation.toValue = Double.pi / 2
rotationAnimation.duration = 0.5
rotationAnimation.fillMode = .forwards
rotationAnimation.isRemovedOnCompletion = false
playerLayer.add(rotationAnimation, forKey: "rotationAnimation")
Keep the Final Position
Core Animation only animates the presentation layer.
After the animation completes, update the actual transform:
CATransaction.begin()
CATransaction.setCompletionBlock {
playerLayer.transform = CATransform3DMakeRotation(.pi / 2, 0, 0, 1)
}
playerLayer.add(rotationAnimation, forKey: "rotationAnimation")
CATransaction.commit()
Rotating from Portrait to Landscape
A common requirement in video applications is transitioning from portrait mode to fullscreen landscape mode.
Example
UIView.animate(withDuration: 0.4) {
self.videoView.transform = CGAffineTransform(rotationAngle: .pi / 2)
self.videoView.frame = UIScreen.main.bounds
}
This:
- Rotates the view.
- Expands it to fullscreen.
- Creates a landscape viewing experience.
Animating an AVPlayerLayer Added Dynamically
Suppose you create a player layer:
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspectFill
self.view.layer.addSublayer(playerLayer)
You can immediately animate it:
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = 0
animation.toValue = Double.pi / 2
animation.duration = 0.5
playerLayer.add(animation, forKey: "rotate")
Removing a Layer After Rotation
Sometimes a transition layer should disappear after the animation finishes.
CATransaction.begin()
CATransaction.setCompletionBlock {
playerLayer.removeFromSuperlayer()
}
playerLayer.add(animation, forKey: "rotate")
CATransaction.commit()
This ensures the layer is removed only after the animation completes.
Rotating a View with Auto Layout
When Auto Layout is used, rotation can affect constraints.
After changing frames or transforms:
self.view.layoutIfNeeded()
This forces Auto Layout to update immediately.
Common Rotation Angles
| Degrees | Radians |
|---|---|
| 90° | .pi / 2 |
| 180° | .pi |
| 270° | 3 * .pi / 2 |
| 360° | 2 * .pi |
Example:
view.transform = CGAffineTransform(rotationAngle: .pi)
Rotates the view 180 degrees.
Best Practices
Use UIView animations for UI elements
UIView.animate(withDuration: 0.3) {
view.transform = CGAffineTransform(rotationAngle: .pi / 2)
}
Use Core Animation for layers
CABasicAnimation(keyPath: "transform.rotation.z")
Update the final transform
Always set the actual transform after the animation finishes.
Remove temporary layers safely
Use:
CATransaction.setCompletionBlock
instead of arbitrary delays.
Complete Example: Rotate Video Layer 90 Degrees
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = 0
animation.toValue = Double.pi / 2
animation.duration = 0.5
CATransaction.begin()
CATransaction.setCompletionBlock {
playerLayer.transform = CATransform3DMakeRotation(.pi / 2, 0, 0, 1)
}
playerLayer.add(animation, forKey: "rotate")
CATransaction.commit()
Conclusion
Rotating views and video layers is a common requirement in media-rich iOS applications. For standard UI elements, CGAffineTransform provides a simple solution. For video playback and other Core Animation layers, CATransform3D and CABasicAnimation offer greater flexibility and smoother transitions.
By combining rotation animations with proper layout updates and completion handlers, you can create seamless portrait-to-landscape transitions and professional fullscreen video experiences in Swift 5 applications.


