Circular Rotating Gradient Ring-Swift & XCode

Add a rotating gradient ring around any circular view — FAST

Charlie Arcodia
Analytics Vidhya
3 min readOct 21, 2019

--

Prerequisites

A basic understanding of Swift and iOS Development.

Jumping in

A unique simplistic style can make your application stand out and add a nice feel. Using gradients correctly could be exactly what’s needed to spice up the UI! Let’s get started.

Add Some Views

We need a UIView and a UIImageView. Add these two blocks. Name them anything you would like. I chose profilePhotoRingView and profilePhoto. Make sure you use your own image name though. Being explicit with your naming conventions will help out big time as the application scales and more devs join the team!

lazy var profilePhotoRingView : UIView = {let oli = UIView()oli.translatesAutoresizingMaskIntoConstraints = falseoli.backgroundColor = .clearoli.isUserInteractionEnabled = trueoli.clipsToBounds = trueoli.layer.masksToBounds = truereturn oli}()lazy var profilePhoto : UIImageView = {let oli = UIImageView()let image = UIImage(named : "demo_wall")?.withRenderingMode(.alwaysOriginal)oli.image = imageoli.translatesAutoresizingMaskIntoConstraints = falseoli.backgroundColor = UIColor .whiteoli.contentMode = .scaleAspectFilloli.layer.masksToBounds = trueoli.layer.borderColor =  UIColor .white.cgColoroli.layer.borderWidth = 1.5oli.isUserInteractionEnabled = truereturn oli}()

Add and Constrain

Add the profilePhotoRingView first so it appears under the profilePhoto. Call the addViews function in the viewDidLoad.

func addViews() {self.view.addSubview(profilePhotoRingView)self.view.addSubview(profilePhoto)
self.profilePhotoRingView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0).isActive = true
self.profilePhotoRingView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0).isActive = trueself.profilePhotoRingView.heightAnchor.constraint(equalToConstant: 50).isActive = trueself.profilePhotoRingView.widthAnchor.constraint(equalToConstant: 50).isActive = trueself.profilePhotoRingView.layer.cornerRadius = 25self.profilePhoto.centerYAnchor.constraint(equalTo: self.profilePhotoRingView.centerYAnchor, constant: 0).isActive = trueself.profilePhoto.centerXAnchor.constraint(equalTo: self.profilePhotoRingView.centerXAnchor, constant: 0).isActive = trueself.profilePhoto.heightAnchor.constraint(equalToConstant: 48).isActive = trueself.profilePhoto.widthAnchor.constraint(equalToConstant: 48).isActive = trueself.profilePhoto.layer.cornerRadius = 24}

Gradient Setup

Add the gradientLayer variable and a Boolean to control viewDidLayoutSubviews().

var gradientLayer: CAGradientLayer!var hasViewBeenLaidOut : Bool = false

Add the handleGradientLayer function.

func handleGradientLayer() {self.gradientLayer = CAGradientLayer()self.gradientLayer.frame = profilePhotoRingView.boundsself.gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)self.gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)self.gradientLayer.colors = [UIColor .blue.withAlphaComponent(1.0).cgColor,UIColor .blue.withAlphaComponent(0.9).cgColor,UIColor .blue.withAlphaComponent(0.8).cgColor,UIColor .blue.withAlphaComponent(0.7).cgColor,UIColor .orange.withAlphaComponent(0.6).cgColor,UIColor .orange.withAlphaComponent(0.5).cgColor,UIColor .orange.withAlphaComponent(0.4).cgColor,UIColor .orange.withAlphaComponent(0.3).cgColor,UIColor .orange.withAlphaComponent(0.2).cgColor,UIColor .orange.withAlphaComponent(0.1).cgColor]self.profilePhotoRingView.layer.addSublayer(self.gradientLayer)self.addGradientRingRotation()}

Why so many colors?! This allows for the decending fading effect on top of the gradient, very cool! One error here though, let’s add the addGradientRingRotation function. Firstly, add the CAAnimationDelegate protocol.

func addGradientRingRotation() {let fullRotation = CABasicAnimation(keyPath: "transform.rotation")fullRotation.delegate = selffullRotation.fromValue = NSNumber(floatLiteral: 0)fullRotation.toValue = NSNumber(floatLiteral: Double(CGFloat.pi * 2))fullRotation.duration = 3.0fullRotation.repeatCount = Float.infinityfullRotation.isRemovedOnCompletion = falseprofilePhotoRingView.layer.add(fullRotation, forKey: "360")}

Easy right! Now, isRemovedOnCompletion will make sure your gradient keeps spinning if you exit the application and return — This is just one possible implementation.

Lastly, let’s add the handleGradientLayer function to viewDidLayoutSubviews().

override func viewDidLayoutSubviews() {super.viewDidLayoutSubviews()if self.hasViewBeenLaidOut == false {self.handleGradientLayer()self.hasViewBeenLaidOut = true}}

That’s it! Now watch your gradient spin in all her glory! Feel free to play with the duration and alpha values of the gradient to get the exact look you’re after! If you would like to see more gradient implementations, let me know in the comments below!

--

--

Charlie Arcodia
Analytics Vidhya

iOS Engineer • Techstars Alumnus • Entrepreneur • CTO @ spectatAR