This is the 22nd day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

This is the desired effect, mainly the following font gradient animation and right pull gesture animation:

Create the required controls first:

class ViewController: UIViewController {
    let timeLabel = UILabel()
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view.addSubview(timeLabel)
        view.backgroundColor = .gray
        timeLabel.text = "9:42"
        timeLabel.font = UIFont.systemFont(ofSize: 72)
        timeLabel.textColor = .white
        timeLabel.frame = CGRect(x: 0, y: 100, width: timeLabel.intrinsicContentSize.width, height: timeLabel.intrinsicContentSize.height)
        timeLabel.center.x = view.center.x
        
    }


}
Copy the code

Then create a file and write a class that inherits from UIView to write the animated interface.

import UIKit
import QuartzCore

class AnimatedMaskLabel: UIView {

}
Copy the code

CAGradientLayer is another subclass of CALayer for gradient layers. Create a CAGradientLayer here to do the gradient. here

  • StartPoint and endPoint define the direction of the gradient and its start and end
  • Colors is an array of Colors for gradients
  • Location: The location of each gradient point. The range is 0-1. The default is 0.
let gradientLayer: CAGradientLayer = { let gradientLayer = CAGradientLayer() // Configure the gradient here gradientLayer.startPoint = Gradientlayer. endPoint = gradientLayer.endPoint (x: 0.0, y: 0.5) gradientLayer.endPoint = gradientLayer.endPoint (x: 1.0, y: 1.0) Let colors = [uicolor.yellow. CgColor, uicolor.orange. CgColor, uicolor.cyan.cgcolor, UIColor.red.cgColor, UIColor.yellow.cgColor ] gradientLayer.colors = colors let locations: [NSNumber] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.25] gradientLayer. Locations = gradientLayer}()Copy the code

In layoutSubviews, set the gradient frame. Here, set the width to three screen widths to make the animation look smoother.

 override func layoutSubviews() {
    gradientLayer.frame = CGRect(
      x: -bounds.size.width,
      y: bounds.origin.y,
      width: 3 * bounds.size.width,
      height: bounds.size.height)
  }
Copy the code

You then need to declare a text, and when text is assigned, render the text as an image, and then use that image to create a mask on the gradient layer.

 var text: String! {
    didSet {
      setNeedsDisplay()

      let image = UIGraphicsImageRenderer(size: bounds.size)
        .image { _ in
          text.draw(in: bounds, withAttributes: textAttributes)
        }

      let maskLayer = CALayer()
      maskLayer.backgroundColor = UIColor.clear.cgColor
      maskLayer.frame = bounds.offsetBy(dx: bounds.size.width, dy: 0)
      maskLayer.contents = image.cgImage

      gradientLayer.mask = maskLayer
    }
  }
Copy the code

You also need to create a text attribute for the text

let textAttributes: [NSAttributedString.Key: Any] = { let style = NSMutableParagraphStyle() style.alignment = .center return [ .font: UIFont( name: "Helveticaneue-thin ", size: 28.0)!,. ParagraphStyle: style]}()Copy the code

Finally add gradientLayer as its child view in didMoveToWindow and animate gradientLayer.

override func didMoveToWindow() { super.didMoveToWindow() layer.addSublayer(gradientLayer) let gradientAnimation = CABasicAnimation(keyPath: "Locations") gradientAnimation. FromValue = [0.0, 0.0, 0.0, 0.0, 0.0, 0.25] gradientAnimation. ToValue = [0.65, 0.8, 0.85, 0.9, 0.95, 1.0] gradientAnimation. Duration = 3.0 gradientAnimation. RepeatCount = Float. Infinity gradientLayer.add(gradientAnimation, forKey: nil) }Copy the code

And then I’m going to add this view to the viewController. Declare an animateLabel

    let animateLabel = AnimatedMaskLabel()
Copy the code

And then in viewDidLoad add the animateLabel to the child view and set the properties so that the animateLabel has a gradient animation.

view.addSubview(animateLabel)
   animateLabel.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height - 200, width: 200, height: 40)
   animateLabel.center.x = view.center.x
   animateLabel.backgroundColor = .clear
   animateLabel.text = "Slide to reveal"
Copy the code

Next add the swipe gesture to the animateLabel and set the swipe direction to swipe right.

   let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSlide))
        swipeGesture.direction = .right
        animateLabel.addGestureRecognizer(swipeGesture)
        
Copy the code

Then animate the response method by creating a temporary variable and leaving it out of the screen, then move the timeLabel up and the animateLabel down for the first animation, and then move the Image to the middle of the screen. Then create an animation to restore the timeLabel and animateLabel, move the image out of the screen, and remove the image.

@objc func handleSlide() { // reveal the meme upon successful slide let image = UIImageView(image: UIImage(named: "meme")) image.center = view.center image.center.x += view.bounds.size.width view.addSubview(image) Uiview.animate (withDuration: 0.33, delay: 0.0, animations: {the self. The timeLabel. Center. - y = 200.0 self. AnimateLabel. Center. + y = 200.0 image. The center. The x - = self. The bounds. Size. The width}, Animate (withDuration: 0.33, Delay: 1.0, animations: {the self. The timeLabel. Center. + y = 200.0 self. AnimateLabel. Center. The y - = 200.0 image. Center. X + = self. The bounds. Size. Width}, completion: {_ in image.removeFromSuperview() } ) }Copy the code

That completes the animation, complete code:

import UIKit class ViewController: UIViewController { let timeLabel = UILabel() let animateLabel = AnimatedMaskLabel() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.addSubview(timeLabel) view.addSubview(animateLabel) view.backgroundColor = .gray timeLabel.text = "9:42" timeLabel.font = UIFont.systemFont(ofSize: 72) timeLabel.textColor = .white timeLabel.frame = CGRect(x: 0, y: 100, width: timeLabel.intrinsicContentSize.width, height: timeLabel.intrinsicContentSize.height) timeLabel.center.x = view.center.x animateLabel.frame = CGRect(x: 0, y: UIScreen.main.bounds.size.height - 200, width: 200, height: 40) animateLabel.center.x = view.center.x animateLabel.backgroundColor = .clear animateLabel.text = "Slide to reveal" let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSlide)) swipeGesture.direction = .right animateLabel.addGestureRecognizer(swipeGesture) } @objc func handleSlide() { // reveal the meme upon successful slide let image = UIImageView(image: UIImage(named: "meme")) image.center = view.center image.center.x += view.bounds.size.width view.addSubview(image) Uiview.animate (withDuration: 0.33, delay: 0.0, animations: {the self. The timeLabel. Center. - y = 200.0 self. AnimateLabel. Center. + y = 200.0 image. The center. The x - = self. The bounds. Size. The width}, Animate (withDuration: 0.33, Delay: 1.0, animations: {the self. The timeLabel. Center. + y = 200.0 self. AnimateLabel. Center. The y - = 200.0 image. Center. X + = self. The bounds. Size. Width}, completion: {_ in image.removeFromSuperview() } ) } }Copy the code
import UIKit import QuartzCore class AnimatedMaskLabel: UIView { let gradientLayer: CAGradientLayer = { let gradientLayer = CAGradientLayer() // Configure the gradient here gradientLayer.startPoint = Gradientlayer. endPoint = gradientLayer.endPoint (x: 0.0, y: 0.5) gradientLayer.endPoint = gradientLayer.endPoint (x: 1.0, y: 1.0) Let colors = [uicolor.yellow. CgColor, uicolor.orange. CgColor, uicolor.cyan.cgcolor, UIColor.red.cgColor, UIColor.yellow.cgColor ] gradientLayer.colors = colors let locations: [NSNumber] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.25] gradientLayer. Locations = Locations Return gradientLayer}() var text: String! { didSet { setNeedsDisplay() let image = UIGraphicsImageRenderer(size: bounds.size) .image { _ in text.draw(in: bounds, withAttributes: textAttributes) } let maskLayer = CALayer() maskLayer.backgroundColor = UIColor.clear.cgColor maskLayer.frame = bounds.offsetBy(dx: bounds.size.width, dy: 0) maskLayer.contents = image.cgImage gradientLayer.mask = maskLayer } } let textAttributes: [NSAttributedString.Key: Any] = { let style = NSMutableParagraphStyle() style.alignment = .center return [ .font: UIFont( name: "HelveticaNeue - Thin," the size: 28.0)!. ParagraphStyle: style ] }() override func layoutSubviews() { layer.borderColor = UIColor.green.cgColor gradientLayer.frame = CGRect( x: -bounds.size.width, y: bounds.origin.y, width: 3 * bounds.size.width, height: bounds.size.height) } override func didMoveToWindow() { super.didMoveToWindow() layer.addSublayer(gradientLayer) let gradientAnimation = CABasicAnimation(keyPath: "Locations") gradientAnimation. FromValue = [0.0, 0.0, 0.0, 0.0, 0.0, 0.25] gradientAnimation. ToValue = [0.65, 0.8, 0.85, 0.9, 0.95, 1.0] gradientAnimation. Duration = 3.0 gradientAnimation. RepeatCount = Float. Infinity gradientLayer.add(gradientAnimation, forKey: nil) } }Copy the code