Swift: Create a slide-unlock text animation

Source: Internet
Author: User
Recently, let's find out and play with Facebook paper. The "slide to unlock your phone" effect is everywhere. The flickering little flickered a little cool feeling. So I'm going to study it. What I thought was that this effect can be achieved with CAGradientLayer and a small animation. The effect of "slide to unlock":

 

Of course, first you need to display this "slide to unlock" text. Here we use a simple UILabel to solve this problem.

   
 var textExampleLabel: UILabel!

    override func viewDidLoad () {
        super.viewDidLoad ()
        
        textExampleLabel = UILabel (frame: CGRectMake (10, 100, UIScreen.mainScreen (). bounds.size.width-20, 30))
        textExampleLabel.text = "slide to unlock your phone, slide to unlock your"
        self.view.addSubview (textExampleLabel)
    }

Label as a member variable (property), initialized in the viewDidLoad method and assigned to the "slide to unlock" text.

Then use Gradient Layer to mask this text. Let's see how to prepare this mask. To use CALayer, you must not be short of the premise that you need to introduce QuartzCore.

import QuartzCore
Later, in order to meet the gradient mask that comes later, we need to refactor a part of the code. Make the entire background color black and the label text white. It seems that the unlocked animation effect is more obvious under the strong black and white contrast. Refactored code:

      
  self.view.backgroundColor = UIColor.blackColor ()
        
        textExampleLabel = UILabel (frame: CGRectMake (10, 100, UIScreen.mainScreen (). bounds.size.width-20, 30))
        textExampleLabel.text = "slide to unlock your phone, slide to unlock yo"
        textExampleLabel.backgroundColor = UIColor.blackColor () // background color-> black
        textExampleLabel.textColor = UIColor.whiteColor () // foreground color-> white
        self.view.addSubview (textExampleLabel)

These are all in the viewDidLoad method.

Let's start adding masks:

      
  var gradientMask = CAGradientLayer ()
        let colors: Array <AnyObject> = [UIColor.blackColor (). CGColor, UIColor.whiteColor (). CGColor, UIColor.blackColor (). CGColor]
        gradientMask.colors = colors
        
        
        textExampleLabel.layer.mask = gradientMask

After running out, you will be startled. Because it's all dark. . .

This is because the mask property needs to use the transparent part of the color. That is to say, a given changed color needs to have a part of transparent or translucent color. Such a gradient layer can function as a mask of another layer. Another problem that needs to be paid attention to is that the above gradientMask also needs a frame. Generally this value is the bounds of the view where the mask property is located. Don't misuse the frame, then gradientMask will mask to the wrong place. After completing the code, it is as follows:
        var testGradient = CAGradientLayer ()
        testGradient.frame = self.textExampleLabel.bounds
        
        testGradient.colors = [UIColor (white: 1.0, alpha: 0.3) .CGColor, UIColor.yellowColor (). CGColor, UIColor (white: 1.0, alpha: 0.3) .CGColor]
        testGradient.startPoint = CGPointMake (0, 0.5)
        testGradient.endPoint = CGPointMake (1, 0.5)
        testGradient.locations = [0, 0.15, 0.3]

The start point and end point are represented in the layer's coordinate system. Not the usual x and y used in positioning frames. For example, when (0.5, 0.5), it represents the center of this layer, center point. (0,0.5) represents the midpoint of the injured edge of the layer, while the corresponding (0,0.5) represents the midpoint of the lower edge. The start point and end point here are the midpoints of the left and right edges, respectively. The boundary of the gradient color that appears at the end must be perpendicular to this point. This is also a very important rule.
The location of the gradient layer is used to specify the end position of each color. Here are 0, 0.15 and 0.3, respectively. These points can be understood here as the percentage distribution along the color gradient line, that is, the line connecting the start point and the end point. However, the last bit of effect is not there. Therefore, the last color continues to the end of the gradient layer.

Here you can clearly see that the color change is from UIColor (white: 1.0, alpha: 0.3) .CGColor to white and then the rest are UIColor (white: 1.0, alpha: 0.3) .CGColor.

At this point, we should let this effect move. How can you try animation without moving? !!

First fill in the sentence just missed:

self.textExampleLabel.layer.mask = testGradient
The way to add animation is relatively simple. Used is the ancient core animation: CABasicAnimation. This animation is applied to the locations property of the gradient layer. So the initialization of this animation should look like this:

var testAnimation = CABasicAnimation (keyPath: "locations")
Then, the animation is from one location to another. Just like the unlock screen of the iPhone we see, highlight a part of the text, repeat from time to time. Until the screen goes dark.

       
 var testAnimation = CABasicAnimation (keyPath: "locations")
        testAnimation.fromValue = [0, 0.15, 0.3]
        testAnimation.toValue = [1-0.3, 1-0.15, 1.0];
        testAnimation.repeatCount = 10000
        testAnimation.duration = 0.3
        testAnimation.delegate = self

Here we set the color gradient from 0 to 0.15 and then to 0.3. This is the beginning, so what should the end be, that is, there are three colors on the length of 0.3, so it is from 1.0-0.3, then 1.0-0.15 and finally 1.0. What is missing in the middle is automatically filled by animation.

OK, let the animation work:

testGradient.addAnimation (testAnimation, forKey: "TEST")
Just add the animation that was just initialized and configured to the layer. The animation of the layer will start to work. As for the value of forKey, it can be arbitrary, and nothing can be given. Run the code and you will see the effect of this animation.

However, if you look closely at this seemingly perfect animation, you will find. The text effect highlighted in white has no effect on the first few letters. At the end, the white highlighting effect did not appear on the last few words. Therefore, at this time, the coordinate system of the layer we mentioned earlier will be used. The x values of the start point and end point are specified at 0 and 1. That is to say, gray will appear from 0 to 0.15. At the end of the animation, gray will appear between 1.0-0.15 to 1.0. Therefore, you need to move the initial x value forward and the last x value backward. That is, the initial x value becomes negative, and the final x value should be 1.0 + some value. So, here we set the start point and end point to:
        testGradient.startPoint = CGPointMake (-0.3, 0.5)
        testGradient.endPoint = CGPointMake (1 + 0.3, 0.5)

At this point, this animation is running. Well, everything is perfect. . .

but. . . But again, what if this effect appears in many places in the app? Should we reuse the code in the simplest and most direct way? This is very rudimentary and very shameful and will also set yourself a time bomb. If you need to modify the gradient color, etc., and you forget to modify the code somewhere. . .

We have to refactor this code, so that when using this effect anywhere, we can directly use the function code we refactored to achieve this effect very simply.

Add a new swift file. Abstract our "slide to unlock" animation function in this file:

The new class here is inherited from NSObject, because we only need to act on UIView properties added here later, and it does not need to be a subclass of UIView itself.

What do we need in this class? A subclass of UIView that can set the mask. The translucent color of the gradient layer of the mask (when there is no highlight) and the highlight color (white). How many times does this animation continue to be executed repeatedly, and how long does each execution take ... In short, basically these things. So take a look at our definition:

    
var animationView: UIView?
    var notHighlightColor: UIColor!
    var highlightColor: UIColor!
    var currentAnimation: CABasicAnimation?
    var effectWidth: CGFloat = 20.0 // width of the gradient colors will take effect
    
    let repeatCount: Float = 10000000 // here, we will let the animation repeat like forever
    let animationDuration: CFTimeInterval = 0.5
    let kTextAnimationKey = "TextAnimation"

In addition to the main needs we said above, there are some animation member variables and The key value of the animation. To delete the corresponding animation when the animation stops executing later, instead of deleting other animations that may be added to this layer.

Start the animation:
    override init () {
        notHighlightColor = UIColor (white: 1.0, alpha: 0.3)
        highlightColor = UIColor.whiteColor ()
    }

At initialization time, non-highlighted colors and highlighted colors are initialized.

To start the animation:

func start () {
        if self.animationView == nil {
            print ("animtion view is nil!")
            return
        }
        
        // clear things used last time
        self.stop ()
        
        var gradientMask = CAGradientLayer ()
        gradientMask.frame = self.animationView! .bounds
        
        var gradientSize = self.effectWidth / CGRectGetWidth (self.animationView! .frame)
        
        var startLocations: Array <AnyObject> = [0, gradientSize / 2.0, gradientSize]
        var endLocations: Array <AnyObject> = [1.0-gradientSize, 1.0-(gradientSize / 2.0), 1.0]
        
        var colors: Array <AnyObject> = [self.notHighlightColor.CGColor, self.highlightColor.CGColor, self.notHighlightColor.CGColor]
        gradientMask.colors = colors
        gradientMask.locations = startLocations
        gradientMask.startPoint = CGPointMake (-gradientSize, 0.5)
        gradientMask.endPoint = CGPointMake (1 + gradientSize, 0.5)
        
        self.animationView! .layer.mask = gradientMask
        
        self.currentAnimation = CABasicAnimation (keyPath: "locations")
        self.currentAnimation! .fromValue = startLocations
        self.currentAnimation! .toValue = endLocations
        self.currentAnimation! .repeatCount = self.repeatCount
        self.currentAnimation! .duration = self.animationDuration
        self.currentAnimation! .delegate = self
        
        gradientMask.addAnimation (self.currentAnimation, forKey: kTextAnimationKey)
    }

In the method, first determine whether the UIView subclass of the animation exists, and if it does not exist, return immediately. If it exists, put all the code of the main function we just refactored here to perform the animation. What changes here is that the area of the gradient color can be specified in the program, not our hard code in the code at the beginning. It is important to note in programming that it is best not to have a hard code situation. In the worst case, you need to set this as a constant property. Hard code left in the code will almost certainly cause bugs!

Let's look at the stop method called in the start method. It is mainly clear about the relevant things in the last animation execution. Avoid interference.

    func stop () {
        if self.animationView! = nil && self.animationView? .layer.mask! = nil {
            self.animationView? .layer.mask.removeAnimationForKey (kTextAnimationKey)
            self.animationView? .layer.mask = nil
            self.currentAnimation = nil
        }
    }
Here is clear the layer mask and the animation on the mask.

Finally, the proxy method animationDidStop (anim: CAAnimation !, finished flag: Bool). When this method is executed, the animation has stopped. Here we can also execute our stop method.

  
  override func animationDidStop (anim: CAAnimation !, finished flag: Bool) {
        if anim == self.currentAnimation {
            self.stop ()
        }
    }

After the refactoring is complete, see how it should be used. We have exposed the calling interface to other code, as mentioned earlier. The UIView subclass that performs this animation, and the length of the gradient color:

   
     self.view.backgroundColor = UIColor.blackColor ()
        
        textExampleLabel = UILabel (frame: CGRectMake (10, 100, UIScreen.mainScreen (). bounds.size.width-20, 30))
        textExampleLabel.text = "slide to unlock your phone, slide to unlock yo"
        textExampleLabel.backgroundColor = UIColor.blackColor () // background color-> black
        textExampleLabel.textColor = UIColor.whiteColor () // foreground color-> white
        self.view.addSubview (textExampleLabel)
        
        self.textAnimation = TextAnimation ()
        self.textAnimation.animationView = textExampleLabel
        self.textAnimation.effectWidth = 50.0

Then execute the animation after the view appears:

self.textAnimation.start ()
OK, now look at all the code after refactoring:

import UIKit
import QuartzCore

class ViewController: UIViewController {
    
    var textExampleLabel: UILabel!
    var textAnimation: TextAnimation!

    override func viewDidLoad () {
        super.viewDidLoad ()
        
        self.view.backgroundColor = UIColor.blackColor ()
        
        textExampleLabel = UILabel (frame: CGRectMake (10, 100, UIScreen.mainScreen (). bounds.size.width-20, 30))
        textExampleLabel.text = "slide to unlock your phone, slide to unlock yo"
        textExampleLabel.backgroundColor = UIColor.blackColor () // background color-> black
        textExampleLabel.textColor = UIColor.whiteColor () // foreground color-> white
        self.view.addSubview (textExampleLabel)
        
        self.textAnimation = TextAnimation ()
        self.textAnimation.animationView = textExampleLabel
        self.textAnimation.effectWidth = 50.0
    }
    
    override func viewDidAppear (animated: Bool) {
        super.viewDidAppear (animated)
        
        self.textAnimation.start ()
    }

    override func didReceiveMemoryWarning () {
        super.didReceiveMemoryWarning ()
        // Dispose of any resources that can be recreated.
    }
}

Finished!

Reference: https://github.com/jonathantribouharet/JTSlideShadowAnimation

 

Swift: create sliding unlock text animation

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.