How to Rotate a UIView or AVPlayerLayer by 90 Degrees with Animation in Swift 5

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:

  • CGAffineTransform
  • CATransform3D
  • 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:

  1. Rotates the view.
  2. Expands it to fullscreen.
  3. 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

DegreesRadians
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.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back