Overview
Hello Everyone, Hope you doing well and Having a nice day. In this article, we are going to focus on most popular and trending Facebook Shimmer Animation for data loading in UITableView, UICollectionView or in any UIView. Nowadays, many applications are using this type of animation with their respective design and look. Personally, I like latest update of Linkedin app, the way they are showing animation of loading graph with line arrow.
If you are an iOS user, then you are familiar with fancy slide to unlock animation.
So I decided to give it a shot. I will help you implement shimmer animation for your app without using any third party frameworks by keeping it simple, easy and native.
Following GIF will show the demonstration of this article.
Performance. Stability. Features.
Coding
Before writing code, I thought it would be better to have my own property (in UIView using @IBInspectable) to easily enable animation from storyboard
@IBInspectable var shimmerAnimation: Bool { get { return isAnimate } set { self.isAnimate = newValue } }
We can not access IBInspectable value at runtime, but with the help of associatedObject its possible, it will return boolean value using compute variable isAnimate.
fileprivate var isAnimate: Bool { get { return objc_getAssociatedObject(self, &associateObjectValue) as? Bool ?? false } set { return objc_setAssociatedObject(self, &associateObjectValue, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) } }
Now its very simple, open the storyboard and select the targeted UIView which need to be animated. Go to attributes inspector you will find our property ‘Shimmer Animation’. By default it is off, we need to turn it on.
So far so good. Now, we require a recursive function which will return all views including its subviews.
func subviewsRecursive() -> [UIView] { return subviews + subviews.flatMap { $0.subviewsRecursive() } }
Here we don’t want all views but only the view with ‘shimmer animation’ true.
func getSubViewsForAnimate() -> [UIView] { var obj: [UIView] = [] for objView in view.subviewsRecursive() { obj.append(objView) } return obj.filter({ (obj) -> Bool in obj.shimmerAnimation }) }
That’s it. We can start animation using the startAnimation function. In below method, we are going to mask the UIView using the CAGradientLayer also animate with CABasicAnimation.
We need to set start and end point of gradient effect to object of gradientLayer with colors and frame according to animateView. At last, mask the animateView layer with gradientLayer.
For the CABasicAnimation it requires keyPath string so be specific with the key. It plays an important role for the animation. Thus, pass the duration of animation alone with from and to value. At last, using gradientLayer add animation object.
func startAnimation() { for animateView in getSubViewsForAnimate() { animateView.clipsToBounds = true let gradientLayer = CAGradientLayer() gradientLayer.colors = [UIColor.clear.cgColor, UIColor.white.withAlphaComponent(0.8).cgColor, UIColor.clear.cgColor] gradientLayer.startPoint = CGPoint(x: 0.7, y: 1.0) gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.8) gradientLayer.frame = animateView.bounds animateView.layer.mask = gradientLayer let animation = CABasicAnimation(keyPath: "transform.translation.x") animation.duration = 1.5 animation.fromValue = -animateView.frame.size.width animation.toValue = animateView.frame.size.width animation.repeatCount = .infinity gradientLayer.add(animation, forKey: "") } }
To stop the animation just remove all the animation from layer and nil mask layer.
func stopAnimation() { for animateView in getSubViewsForAnimate() { animateView.layer.removeAllAnimations() animateView.layer.mask = nil } }
Please take a look at code. Feel free to ask any query/doubts in below commenting section.