banner



How To Create Loading Animation Ios Swift

With more i.4 one thousand thousand apps in the iOS App Store today, it'due south a existent challenge to make your app stand out. You have a very small window of opportunity to capture the attending of your users before your app ends up in the big black pigsty of obscurity.

In that location'southward no amend place to showtime wowing your users than at the loading screen of your app, where you can add a delightful animation that serves as a forerunner to your on-boarding or authentication workflow.

In this tutorial you volition learn how to brand such an animation. You'll learn how to build it up piece-by-slice, utilising avant-garde techniques to create a fluid and captivating animation.

Getting Started

Download the starter projection for this tutorial here, salvage it to a user-friendly location and open it in Xcode.

Open up HolderView.swift. In this UIView subclass, yous will add and breathing the following sublayers (constitute in the Layers subgroup) as shown in the animation in a higher place:

  • OvalLayer.swift: This is the beginning layer, which expands from nothing size and so wobbles for a brusk menses of time.
  • TriangleLayer.swift: This next layer appears while the OvalLayer is wobbling. When this view rotates, OvalLayer contracts dorsum to zero size leaving just the TriangleLayer visible.
  • RectangleLayer.swift: This layer serves as a visual container of sorts for the TriangleLayer.
  • ArcLayer.swift: This layer fills the RectangleLayer with an animation result that'due south very like to a drinking glass being filled with water.

Open up OvalLayer.swift; the starter project already contains the code to initialize this layer and all the Bezier paths you'll use in your animations. You lot'll see that expand(), wobble() and contract() are all empty; y'all'll populate those methods equally you work through the tutorial. All the other *Layer files are structured in a similar fashion.

Finally, open ViewController.swift and take a look at addHolderView(); this method adds an example of HolderView as a subview to the center of the view controller'south view. This view will house all the animations. The view controller just needs to put information technology on the screen, and the view will take care of the actual blitheness lawmaking.

The animateLabel() function is a delegate callback provided by the HolderView class that you will fill in every bit you lot consummate the animation sequence. addButton() merely adds a button to the view so that you can tap and restart the animation.

Build and run your app; you should come across an empty white screen. An empty canvas — the perfect thing on which to start creating your new animations! :]

By the end of this tutorial, your app will look like this:

finalAnimationFullyComplete

And so without further ado, let'south get started!

Adding The Oval

The animation starts with a red oval that expands into view from the centre of the screen and then wobbles effectually a bit.

Open HolderView.swift and declare the following abiding near the top of the HolderView course:

let ovalLayer = OvalLayer()        

Now add together the post-obit function to the bottom of the class:

func addOval() {   layer.addSublayer(ovalLayer)   ovalLayer.expand() }        

This first adds the OvalLayer instance you created above equally a sublayer to the view's layer, then calls expand(), which is one of the stubbed-out functions you lot need to fill in.

Go to OvalLayer.swift and add the post-obit code to aggrandize():

func expand() {   var expandAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")   expandAnimation.fromValue = ovalPathSmall.CGPath   expandAnimation.toValue = ovalPathLarge.CGPath   expandAnimation.duration = animationDuration   expandAnimation.fillMode = kCAFillModeForwards   expandAnimation.removedOnCompletion = false   addAnimation(expandAnimation, forKey: nil) }        

This role creates an example of CABasicAnimation that changes the oval's path from ovalPathSmall to ovalPathLarge. The starter project provides both of these Bezier paths for you. Setting removedOnCompletion to fake and fillMode to KCAFillModeForwards on the animation lets the oval retain its new path once the blitheness has finished.

Finally, open ViewController.swift and add the following line to addHolderView() just below view.addSubview(holderView):

holderView.addOval()        

This calls addOval to kickstart the animation after it has been added to the view controller'due south view.

Build and run your app; your animation should now await like this:

OvalExpandInitial

Wobbling The Oval

With your oval at present expanding into view, the next step is to put some bounce in its pace and make information technology wobble.

Open up HolderView.swift and add together the following part to the bottom of the class:

func wobbleOval() {   ovalLayer.wobble() }        

This calls the stubbed-out method wobble() in OvalLayer.

At present open OvalLayer.swift and add the post-obit code to wobble():

func wobble() {   // i   var wobbleAnimation1: CABasicAnimation = CABasicAnimation(keyPath: "path")   wobbleAnimation1.fromValue = ovalPathLarge.CGPath   wobbleAnimation1.toValue = ovalPathSquishVertical.CGPath   wobbleAnimation1.beginTime = 0.0   wobbleAnimation1.duration = animationDuration        // 2   var wobbleAnimation2: CABasicAnimation = CABasicAnimation(keyPath: "path")   wobbleAnimation2.fromValue = ovalPathSquishVertical.CGPath   wobbleAnimation2.toValue = ovalPathSquishHorizontal.CGPath   wobbleAnimation2.beginTime = wobbleAnimation1.beginTime + wobbleAnimation1.duration   wobbleAnimation2.duration = animationDuration        // 3   var wobbleAnimation3: CABasicAnimation = CABasicAnimation(keyPath: "path")   wobbleAnimation3.fromValue = ovalPathSquishHorizontal.CGPath   wobbleAnimation3.toValue = ovalPathSquishVertical.CGPath   wobbleAnimation3.beginTime = wobbleAnimation2.beginTime + wobbleAnimation2.duration   wobbleAnimation3.duration = animationDuration        // 4   var wobbleAnimation4: CABasicAnimation = CABasicAnimation(keyPath: "path")   wobbleAnimation4.fromValue = ovalPathSquishVertical.CGPath   wobbleAnimation4.toValue = ovalPathLarge.CGPath   wobbleAnimation4.beginTime = wobbleAnimation3.beginTime + wobbleAnimation3.duration   wobbleAnimation4.elapsing = animationDuration        // 5   var wobbleAnimationGroup: CAAnimationGroup = CAAnimationGroup()   wobbleAnimationGroup.animations = [wobbleAnimation1, wobbleAnimation2, wobbleAnimation3,  				     wobbleAnimation4]   wobbleAnimationGroup.duration = wobbleAnimation4.beginTime + wobbleAnimation4.duration   wobbleAnimationGroup.repeatCount = 2   addAnimation(wobbleAnimationGroup, forKey: zero) }        

That'southward a lot of code, just information technology breaks down nicely. Here's what's going on:

  1. Animate from the big path down to being squished vertically.
  2. Modify from a vertical squish to squished both horizontally and vertically.
  3. Swap back to vertical squish.
  4. Cease the blitheness, ending back at the large path.
  5. Combine all of your animations into a CAAnimationGroup and add together this grouping animation to your OvalLayout.

The beginTime of each subsequent animation is the sum of the beginTime of the previous animation and its duration. You echo the animation group twice to give the wobble a slightly elongated feel.

Even though you now have all the code required to produce the wobble animation, you aren't calling your new animation nonetheless.

Go dorsum to HolderView.swift and add together the following line to the finish of addOval():

NSTimer.scheduledTimerWithTimeInterval(0.iii, target: self, selector: "wobbleOval",                                         userInfo: nix, repeats: false)        

Here y'all create a timer that calls wobbleOval() correct after the OvalLayer has finished expanding.

Build and run your app; check out your new animation:

OvalWobbling

It's very subtle, only that'southward an important factor of a truly delightful animation. Y'all don't demand things to be flying all over the screen!

Get-go The Morph

It's time to get a footling fancy! :] You're going to morph the oval into a triangle. To the user'due south centre, this transition should look completely seamless. Yous'll use ii split up shapes of the same colour to brand this work.

Open HolderView.swift and add the following lawmaking to the top of HolderView class, just below the ovalLayer property y'all added earlier:

let triangleLayer = TriangleLayer()        

This declares a constant case of TriangleLayer, just like yous did for OvalLayer.

At present, make wobbleOval() expect like this:

func wobbleOval() {   // ane   layer.addSublayer(triangleLayer) // Add this line   ovalLayer.wobble()      // 2     // Add the code below   NSTimer.scheduledTimerWithTimeInterval(0.9, target: self,                                           selector: "drawAnimatedTriangle", userInfo: cypher,                                           repeats: false)  }        

The code to a higher place does the post-obit:

  1. This line adds the TriangleLayer example y'all initialized earlier as a sublayer to the HolderView's layer.
  2. Since you know that the wobble animation runs twice for a full duration of 1.8, the half-fashion indicate would exist a bang-up place to start the morphing process. You therefore add together a timer that adds drawAnimatedTriangle() afterward a delay of 0.9.

Note: Finding the correct duration or delay for animations takes some trial and error, and can mean the divergence between a practiced animation and a fantastic one. I encourage you to tinker with your animations to get them looking perfect. It can take some time, but it'southward worth it!

Adjacent, add the following role to the lesser of the class:

func drawAnimatedTriangle() {   triangleLayer.breathing() }        

This method is called from the timer that you lot just added to wobbleOval(). It calls the (currently stubbed out) method in triangleLayer which causes the triangle to breathing.

At present open TriangleLayer.swift and add the following code to breathing():

func animate() {   var triangleAnimationLeft: CABasicAnimation = CABasicAnimation(keyPath: "path")   triangleAnimationLeft.fromValue = trianglePathSmall.CGPath   triangleAnimationLeft.toValue = trianglePathLeftExtension.CGPath   triangleAnimationLeft.beginTime = 0.0   triangleAnimationLeft.duration = 0.iii      var triangleAnimationRight: CABasicAnimation = CABasicAnimation(keyPath: "path")   triangleAnimationRight.fromValue = trianglePathLeftExtension.CGPath   triangleAnimationRight.toValue = trianglePathRightExtension.CGPath   triangleAnimationRight.beginTime = triangleAnimationLeft.beginTime + triangleAnimationLeft.duration   triangleAnimationRight.duration = 0.25      var triangleAnimationTop: CABasicAnimation = CABasicAnimation(keyPath: "path")   triangleAnimationTop.fromValue = trianglePathRightExtension.CGPath   triangleAnimationTop.toValue = trianglePathTopExtension.CGPath   triangleAnimationTop.beginTime = triangleAnimationRight.beginTime + triangleAnimationRight.elapsing   triangleAnimationTop.duration = 0.xx      var triangleAnimationGroup: CAAnimationGroup = CAAnimationGroup()   triangleAnimationGroup.animations = [triangleAnimationLeft, triangleAnimationRight,                                        triangleAnimationTop]   triangleAnimationGroup.duration = triangleAnimationTop.beginTime + triangleAnimationTop.duration   triangleAnimationGroup.fillMode = kCAFillModeForwards   triangleAnimationGroup.removedOnCompletion = false   addAnimation(triangleAnimationGroup, forKey: nil) }        

This code animates the corners of TriangleLayer to pop out one-by-one every bit the OvalLayer wobbles; the Bezier paths are already defined for each corner as part of the starter project. The left corner goes first, followed by the right and and so the top. You do this past creating iii instances of a path-based CABasicAnimation that you add to a CAAnimationGroup, which, in turn, you add together to TriangleLayer.

Build and run the app to run across the current land of the blitheness; as the oval wobbles, each corner of the triangle begins to appear until all three corners are visible, like so:

BeginningMorph

Completing The Morph

To consummate the morphing process, you'll rotate HolderView by 360 degrees while you contract OvalLayer, leaving just TriangleLayer lonely.

Open HolderView.swift add the following code to the end of drawAnimatedTriangle():

NSTimer.scheduledTimerWithTimeInterval(0.9, target: self, selector: "spinAndTransform",                                         userInfo: nil, repeats: false)        

This sets up a timer to fire subsequently the triangle animation has finished. The 0.9s time was one time once again determined by trial and error.

Now add the following part to the bottom of the grade:

func spinAndTransform() {   // one   layer.anchorPoint = CGPointMake(0.5, 0.half-dozen)    // ii   var rotationAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")   rotationAnimation.toValue = CGFloat(M_PI * ii.0)   rotationAnimation.duration = 0.45   rotationAnimation.removedOnCompletion = true   layer.addAnimation(rotationAnimation, forKey: null)    // iii   ovalLayer.contract() }        

The timer you created only before calculation this code calls this function once the the oval stops wobbling and all corners of the triangle announced. Here'due south a wait at this role in more particular:

  1. Update the ballast point of the layer to exist slightly below the center of the view. This affords a rotation that appears more natural. This is because the oval and triangle are actually get-go from the center of the view, vertically. So if the view was rotated around its center, then the oval and triangle would appear to move vertically.
  2. Apply a CABasicAnimation to rotate the layer 360 degrees, or two*Pi radians. The rotation is around the z-axis, which is the axis going into and out of the screen, perpendicular to the screen surface.
  3. Call contract() on OvalLayer to perform the animation that reduces the size of the oval until it's no longer visible.

Now open OvalLayer.swift and add the following code to contract():

func contract() {   var contractAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")   contractAnimation.fromValue = ovalPathLarge.CGPath   contractAnimation.toValue = ovalPathSmall.CGPath   contractAnimation.duration = animationDuration   contractAnimation.fillMode = kCAFillModeForwards   contractAnimation.removedOnCompletion = false   addAnimation(contractAnimation, forKey: nil) }        

This sets OvalLayer dorsum to its initial path of ovalPathSmall by applying a CABasicAnimation. This is the exact reverse of aggrandize(), which y'all chosen at the outset of the animation.

Build and run your app; the triangle is the only affair that should be left on the screen one time the blitheness is done:

morphending

Cartoon The Container

In this next part, you're going to breathing the drawing of a rectangular container to create an enclosure. To do this, you'll use the stroke property of RectangleLayer. You'll do this twice, using both ruby and blue as the stroke colour.

Open HolderView.swift and declare 2 RectangularLayer constants every bit follows, underneath the triangleLayer property you added before:

allow redRectangleLayer = RectangleLayer() let blueRectangleLayer = RectangleLayer()        

Next add the following code to the terminate of spinAndTransform():

NSTimer.scheduledTimerWithTimeInterval(0.45, target: self,                                         selector: "drawRedAnimatedRectangle",                                         userInfo: nil, repeats: simulated) NSTimer.scheduledTimerWithTimeInterval(0.65, target: self,                                         selector: "drawBlueAnimatedRectangle",                                         userInfo: nil, repeats: simulated)        

Hither you create two timers that call drawRedAnimatedRectangle() and drawBlueAnimatedRectangle() respectively. Yous draw the ruby-red rectangle showtime, right later the rotation animation is complete. The blue rectangle'south stroke begins as the crimson rectangle's stroke draws close to completion.

Add together the following two functions to the bottom of the class:

func drawRedAnimatedRectangle() {   layer.addSublayer(redRectangleLayer)   redRectangleLayer.animateStrokeWithColor(Colors.red) }    func drawBlueAnimatedRectangle() {   layer.addSublayer(blueRectangleLayer)   blueRectangleLayer.animateStrokeWithColor(Colors.blue) }        

Once y'all add together the RectangleLayer as a sublayer to HolderView, you call animateStrokeWithColor(color:) and pass in the appropriate color to animate the drawing of the border.

Now open RectangleLayer.swift and populate animateStrokeWithColor(color:) as follows:

func animateStrokeWithColor(color: UIColor) {   strokeColor = color.CGColor   var strokeAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")   strokeAnimation.fromValue = 0.0   strokeAnimation.toValue = i.0   strokeAnimation.elapsing = 0.4   addAnimation(strokeAnimation, forKey: nil) }        

This draws a stroke around RectangleLayer by adding a CABasicAnimation to information technology. The strokeEnd key of CAShapeLayer indicates how far around the path to stop stroking. By animating this property from 0 to 1, you create the illusion of the path being fatigued from start to finish. Animating from ane to 0 would create the illusion of the entire path being rubbed out.

Build and run your app to run across how the two strokes expect as they build the container:

containerDraw

Filling In The Container

With your container now in place, the adjacent phase of the animation is to fill it up. The effect you're looking for is that of water filling up a glass. This is a great visual effect and sets things up for a big…splash! :]

Open up HolderView.swift and add the following abiding just beneath the two RectangleLayer properties:

let arcLayer = ArcLayer()        

Now add the following code to the terminate of drawBlueAnimatedRectangle():

NSTimer.scheduledTimerWithTimeInterval(0.40, target: self, selector: "drawArc",                                         userInfo: nil, repeats: false)        

This creates a timer to phone call drawArc() in one case the blue RectangleLayer finishes drawing.

Add the following function to the stop of the class:

func drawArc() {   layer.addSublayer(arcLayer)   arcLayer.animate() }        

This adds the case of ArcLayer created above to the HolderView's layer before you animate in the fill.

Open ArcLayer.swift and add together the post-obit code to animate():

func animate() {   var arcAnimationPre: CABasicAnimation = CABasicAnimation(keyPath: "path")   arcAnimationPre.fromValue = arcPathPre.CGPath   arcAnimationPre.toValue = arcPathStarting.CGPath   arcAnimationPre.beginTime = 0.0   arcAnimationPre.duration = animationDuration        var arcAnimationLow: CABasicAnimation = CABasicAnimation(keyPath: "path")   arcAnimationLow.fromValue = arcPathStarting.CGPath   arcAnimationLow.toValue = arcPathLow.CGPath   arcAnimationLow.beginTime = arcAnimationPre.beginTime + arcAnimationPre.duration   arcAnimationLow.duration = animationDuration        var arcAnimationMid: CABasicAnimation = CABasicAnimation(keyPath: "path")   arcAnimationMid.fromValue = arcPathLow.CGPath   arcAnimationMid.toValue = arcPathMid.CGPath   arcAnimationMid.beginTime = arcAnimationLow.beginTime + arcAnimationLow.duration   arcAnimationMid.duration = animationDuration        var arcAnimationHigh: CABasicAnimation = CABasicAnimation(keyPath: "path")   arcAnimationHigh.fromValue = arcPathMid.CGPath   arcAnimationHigh.toValue = arcPathHigh.CGPath   arcAnimationHigh.beginTime = arcAnimationMid.beginTime + arcAnimationMid.duration   arcAnimationHigh.elapsing = animationDuration        var arcAnimationComplete: CABasicAnimation = CABasicAnimation(keyPath: "path")   arcAnimationComplete.fromValue = arcPathHigh.CGPath   arcAnimationComplete.toValue = arcPathComplete.CGPath   arcAnimationComplete.beginTime = arcAnimationHigh.beginTime + arcAnimationHigh.duration   arcAnimationComplete.duration = animationDuration        var arcAnimationGroup: CAAnimationGroup = CAAnimationGroup()   arcAnimationGroup.animations = [arcAnimationPre, arcAnimationLow, arcAnimationMid,                                    arcAnimationHigh, arcAnimationComplete]   arcAnimationGroup.duration = arcAnimationComplete.beginTime + arcAnimationComplete.duration   arcAnimationGroup.fillMode = kCAFillModeForwards   arcAnimationGroup.removedOnCompletion = imitation   addAnimation(arcAnimationGroup, forKey: goose egg) }        

This blitheness is very similar to the earlier wobble animation; you create a CAAnimationGroup that contains v instances of a path-based CABasicAnimation. Each path has a slightly different arc with increasing height and is function of the starter project. Finally, you employ the CAAnimationGroup to the layer and instruct it to not exist removed on completion and so information technology will retain its state when the animation has finished.

Build and run your app to watch the magic unfold!

ContainerFillCompleted

Completing The Animation

All that'south left to practise is expand the blue HolderView to fill in the entire screen and add a UILabel to the view to serve as the logo.

Open HolderView.swift and add together the post-obit code to the end of drawArc():

NSTimer.scheduledTimerWithTimeInterval(0.90, target: self, selector: "expandView",                                         userInfo: nil, repeats: false)        

This creates a timer that calls expandView() after the ArcLayer fills up the container.

Now, add the post-obit role to the lesser of the same class:

func expandView() {   // ane   backgroundColor = Colors.blue    // ii   frame = CGRectMake(frame.origin.x - blueRectangleLayer.lineWidth,                       frame.origin.y - blueRectangleLayer.lineWidth,                       frame.size.width + blueRectangleLayer.lineWidth * two,                       frame.size.elevation + blueRectangleLayer.lineWidth * 2)    // 3   layer.sublayers = nil      // iv   UIView.animateWithDuration(0.3, filibuster: 0.0, options: UIViewAnimationOptions.CurveEaseInOut,     animations: {       self.frame = self.parentFrame     }, completion: { finished in       cocky.addLabel()     }) }        

Here's what that method does:

  1. The background of the holder view is set to blueish, to match the color you filled the rectangle with.
  2. The frame is expanded to business relationship for the RectangleLayer's stroke width that you lot added earlier.
  3. All sublayers are removed. Now at that place are no oval, no triangle and no rectangle layers.
  4. An animation is added to aggrandize the HolderView to fill the screen. Once that blitheness's done, you call addLabel().

Add the following function to the bottom of the class:

func addLabel() {   delegate?.animateLabel() }        

This only calls the view's delegate role to animate the characterization.

Now open ViewController.swift and add the following lawmaking to animateLabel():

func animateLabel() {   // 1   holderView.removeFromSuperview()   view.backgroundColor = Colors.blue    // 2     var characterization: UILabel = UILabel(frame: view.frame)   label.textColor = Colors.white   characterization.font = UIFont(proper noun: "HelveticaNeue-Thin", size: 170.0)   characterization.textAlignment = NSTextAlignment.Center   characterization.text = "South"   label.transform = CGAffineTransformScale(label.transform, 0.25, 0.25)   view.addSubview(label)    // iii     UIView.animateWithDuration(0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.ane, options: UIViewAnimationOptions.CurveEaseInOut,     animations: ({       characterization.transform = CGAffineTransformScale(characterization.transform, 4.0, 4.0)     }), completion: { finished in       cocky.addButton()     }) }        

Taking each commented department in turn:

  1. Remove HolderView from the view and gear up the view'south background colour to blue.
  2. Create a UILabel with text of 'Due south' to correspond the logo, and add it to the view.
  3. Apply a bound animation to the characterization to scale information technology in. In one case the animation is done, call addButton() to add a button to your view, which, when pressed, repeats the blitheness.

Build and run the awarding, give yourself a pat on the dorsum and have a moment to enjoy what you've congenital! :]

finalAnimationFullyComplete

Where to Go From Here?

You can download the final completed projection here.

This tutorial covered quite a few unlike animation techniques that, when stacked together, create a rather circuitous loading animation that really makes your app smoothen on first run.

From here, feel free to play around with different timings and shapes to see what cool animations y'all can come up up with.

If you want to accept your new found animation skills to the next level, and so I suggest you check out our volume, iOS Animations by Tutorials.

I promise that you had a ton of fun going through this tutorial, and if you have any questions or comments, delight bring together the forum give-and-take below!

Source: https://www.raywenderlich.com/1746-how-to-create-a-complex-loading-animation-in-swift

Posted by: whitfieldlaysence.blogspot.com

0 Response to "How To Create Loading Animation Ios Swift"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel