How to create a typing loader using animation in iOS Swift

Trupti Nayak
4 min readDec 30, 2020

Here’s how I created a typing loader for my chat app, It's pretty simple and straightforward. This article is written inspired by lottie animation. Here I have used CAReplicatorLayer which was something new for me. Start creating a custom view that can be reused in your application. Let's go...

We start by creating a custom UIView class.

final class TypingLoaderView: UIView{private var dotsSuperView: UIViewprivate var dotsBackgroundColor: UIColorlet dotsWidth = 8init(color: UIColor = .white, superView: UIView) { dotsBackgroundColor = color dotsSuperView = superView super.init(frame: .zero) showAnimatingDots() // We will come to this later
}
}

Now let’s break it down into steps.

Step 1: Create a dot.

This is a basic CALayer with the frame, color, and corner radius. Create this method anywhere in the TypingLoaderView class

func createDot() -> CALayer{let dot = CALayer()dot.frame = CGRect(x: 1, y: 1, width: dotsWidth, height: dotsHeight)dot.cornerRadius = dot.frame.width / 2dot.backgroundColor = dotsBackgroundColor.cgColorreturn dot}

Step 2: Replicate the dots

We want to replicate the dots to as many as you want. I would be adding 3 dots. We achieve this using CAReplicatorLayer. This class creates a specified number of sublayers.

func addReplicatorFor(shape: CALayer, noOfInstances: Int, instanceDelay: CFTimeInterval, superView: UIView){let layer = CAReplicatorLayer()layer.frame = CGRect(x: 0, y: 0, width: dotsWidth * 5, height: dotsHeight * 2)layer.contentsGravity = CALayerContentsGravity.centerlayer.addSublayer(shape)layer.instanceCount = noOfInstanceslayer.instanceTransform = CATransform3DMakeTranslation(15, 0, 0)layer.instanceDelay = instanceDelaylayer.position = superView.centerself.layer.addSublayer(layer)}

In the above code snippet, we first create an instance of CAReplicatorLayer, define layer’s frame. contentsGravity will load all the contents of the layer to the center w.r.t bounds rect.

We then add the dot(which is shape here) to the layer and specify the number of dots we want using the instanceCount property.

instanceTransform property will add a transform matrix relative to the dots. instanceDelay will provide a delay to each instance of the sublayer. In this example, we create 3 dots and the delay value is applied to each of them. This delay is useful while we animate the layer. Finally, position it and add it to the TypingLoaderView’s layer

Step 3: Bring it together

Bring the methods together and adding animation. Call the below method in the TypingLoaderView’s initializer.

func showAnimatingDots() {let fromScale: CATransform3D = CATransform3DMakeScale(1, 1, 1)let toScale: CATransform3D = CATransform3DMakeScale(1.4, 1.4, 1)var animationDelay: CFTimeIntervallet noOfInstances: Int = 3//step1: Create dotlet dot = createDot()//step2: add animations for dot- Opacity, y position and transformdot.addAnimationToLayer(withKeyPath: .opacity, from: CGFloat(1.0), to: CGFloat(0.2), duration: 1, repeatCount: .infinity)dot.addAnimationToLayer(withKeyPath: .yPosition, from: dot.position.y, to: circle.position.y + 3, duration: 1.2, repeatCount: Float.infinity)let transformDuration:CFTimeInterval = 0.6dot.addAnimationToLayer(withKeyPath: .transform, from: fromScale, to: toScale, duration: transformDuration, repeatCount: Float.infinity)dot.transform = toScaleanimationDelay = transformDuration / Double(noOfInstances)//step3: replicate dots to 3addReplicatorLayerFor(shape: dot, noOfInstances: noOfInstances, instanceDelay: animationDelay, superView: dotsSuperView) dotsSuperView.addSubview(self)
}

Step 4: Animations!!!

We add opacity animation to slightly fade the dots, y position so that the dots move up and down during animation and finally transform animation to increase the dot size and go back to its normal size. I use CABasicAnimation. This class uses single keyFrame animation for layer properties. Add an extension of CALayer like so:

extension CALayer {func addAnimationToLayer(withKeyPath keyPath: AnimationKeyPath, from: Any, to: Any, duration: CFTimeInterval,  repeatCount: Float) {let animation: CABasicAnimation = CABasicAnimation(withKeyPath: keyPath, from: from, to: to, duration: duration, repeatCount: repeatCount)self.add(animation, forKey: keyPath.rawValue)}}// define a enum to maintain the types of animation (optional) 
enum AnimationKeyPath: String{
case yPosition = "position.y"case transform = "transform"case opacity = "opacity"}

This completes creating a custom typing loader.

Now how do we use it?

Add loader

func createTypingLoader(withColor color: UIColor = .white, xMargin: CGFloat = 0){let dotsContainerView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 20)) // modify x and y according to super viewdotsView = TypingLoaderView(color: color, superView: dotsContainerView) // assuming dotsView is a property of ViewControllerself.view.addSubview(dotsContainerView) // self.view is assuming viewController for this demo}

Remove loader

Add the following method in TypingLoaderView.

func removeLoader(){self.layer.removeAllAnimations()self.removeFromSuperview()}

Calling from viewController or any place like this

dotsView.removeDotsLoader()

Typing loader final looks — Christmas theme loader

Suggestions are welcome

--

--