- Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Here are the animations you want to achieve:Which leaves 🚗. The animation of. First you need to put 🚗. Put the image in Asset. Also declare a carImageView property and the desired image size property. Here we need to create an additional carAnimator for the animation.
private let carSize = CGSize(width: 50, height: 45) private var carImageView: UIImageView! Private var carAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator(Duration: 3.0, Curve:.easeinout, animations: nil)Copy the code
Again, you need to set the size of the carImageView and other properties in setupUI, then make it interactive, add click gestures and response methods to animate the click later, and finally add a child view of the view.
carImageView = UIImageView(frame: CGRect(x: 0, y: view.frame.height - 100, width: carSize.width, height: carSize.height))
carImageView.contentMode = .scaleToFill
carImageView.image = UIImage(named: "car_icon")
carImageView.isUserInteractionEnabled = true
carImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(userTapOnCar)))
view.addSubview(carImageView)
Copy the code
Declare an animateCarToRight method by adding 🚗. AnimateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo: animateLogo
private func animateCarToRight() { carAnimator.stopAnimation(true) carAnimator.addAnimations { // Move car to the bottom right of the screen self.carImageView.frame = CGRect(origin: CGPoint(x: self.view.frame.width - self.carSize.width, y: self.view.frame.height - 100), size: self.carSize) } carAnimator.addCompletion { _ in UIView.animate(withDuration: 0.5, animations: {self. CarImageView. Transform = CGAffineTransform (scaleX: 1.0, y: 1.0)}, completion: { _ in }) } carAnimator.startAnimation() }Copy the code
Next in carImageView judgment carImageView. Click on the response of the method to add frame. The origin. The x and the frame. The width / 2 code, if is greater than the need to move from right to left, less than moving from left to right.
@objc private func userTapOnCar() {
if carImageView.frame.origin.x > view.frame.width/2 {
// Destination is on the right, go back to the left
self.animateCarToLeft()
} else {
// Destination is on the left, go back to the right
self.animateCarToRight()
}
}
Copy the code
We also need to add the animateCarToLeft method, which is similar to the animateCarToRight method, except that we need to change the x value to be moved and the transform value to be flipped.
private func animateCarToLeft() { carAnimator.stopAnimation(true) carAnimator.addAnimations { // Move car to the bottom left of the screen self.carImageView.frame = CGRect(origin: CGPoint(x: 0, y: self.view.frame.height - 100), size: Self. CarSize)} carAnimator. AddCompletion {_ in UIView. The animate (withDuration: 0.5, animations: {self. CarImageView. Transform = CGAffineTransform (scaleX: 1.0, y: 1.0)}, completion: { _ in self.animateCarToRight() }) } carAnimator.startAnimation() }Copy the code
This is where the landing page animation is done. Complete code:
import UIKit
class ViewController: UIViewController {
private let logoSize = CGSize(width: 250, height: 40)
private var logoImageView: UIImageView!
private let loginButtonSize = CGSize(width: 60, height: 60)
var loginButton: UIButton!
private let carSize = CGSize(width: 50, height: 45)
private var carImageView: UIImageView!
private var carAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: 3.0, curve: .easeInOut, animations: nil)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupUI()
animateLogo {
self.animateLoginButton()
self.animateCarToRight()
}
}
private func setupUI() {
// Initialize the logo at the center of screen
logoImageView = UIImageView(frame: CGRect(x: view.frame.width/2 - logoSize.width/2,
y: view.frame.height/2 - logoSize.height/2,
width: logoSize.width,
height: logoSize.height))
logoImageView.contentMode = .scaleToFill
logoImageView.image = UIImage(named: "logo_icon")
logoImageView.isUserInteractionEnabled = true
logoImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(shakeLogo)))
view.addSubview(logoImageView)
// Initialize the logo at the center of screen
loginButton = UIButton(type: .custom)
loginButton.frame = CGRect(x: view.frame.width/2 - loginButtonSize.width/2,
y: view.frame.height/2 - loginButtonSize.height/2,
width: loginButtonSize.width,
height: loginButtonSize.height)
loginButton.center = view.center
loginButton.layer.borderColor = UIColor.brown.cgColor
loginButton.layer.borderWidth = 1
loginButton.layer.cornerRadius = loginButtonSize.width / 2
loginButton.setTitle("Open", for: .normal)
loginButton.setTitleColor(.brown, for: .normal)
loginButton.setTitleColor(UIColor.brown.withAlphaComponent(0.5), for: .highlighted)
loginButton.alpha = 0
view.addSubview(loginButton)
carImageView = UIImageView(frame: CGRect(x: 0, y: view.frame.height - 100, width: carSize.width, height: carSize.height))
carImageView.contentMode = .scaleToFill
carImageView.image = UIImage(named: "car_icon")
carImageView.isUserInteractionEnabled = true
carImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(userTapOnCar)))
view.addSubview(carImageView)
}
@objc private func shakeLogo() {
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.07
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = NSValue(cgPoint: CGPoint(x: logoImageView.center.x - 10, y: logoImageView.center.y))
animation.toValue = NSValue(cgPoint: CGPoint(x: logoImageView.center.x + 10, y: logoImageView.center.y))
logoImageView.layer.add(animation, forKey: "position")
}
private func animateLoginButton() {
// Step 1: Draw the Bezier path
let path = UIBezierPath()
// Start at center left of screen
path.move(to: CGPoint(x: 0, y: view.center.y))
// Add line to the left side -10 px of login button
path.addLine(to: CGPoint(x: loginButton.center.x - loginButtonSize.width - 10,
y: view.center.y))
// Add arc that go to -10 px bottom of login button
path.addArc(withCenter: loginButton.center,
radius: loginButtonSize.height/2 + 10,
startAngle: CGFloat(Double.pi),
endAngle: CGFloat(Double.pi/2),
clockwise: false)
// Add arc that go to 10 px right of login button
path.addArc(withCenter: loginButton.center,
radius: loginButtonSize.height/2 + 10,
startAngle: CGFloat(Double.pi/2),
endAngle: CGFloat(0),
clockwise: false)
// Add line to the center right of screen
path.addLine(to: CGPoint(x: view.frame.width,
y: view.center.y))
// Step 2: Create the shape layer from Bezier path
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.brown.cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineCap = CAShapeLayerLineCap.round
shapeLayer.lineJoin = CAShapeLayerLineJoin.round
shapeLayer.strokeEnd = 0
view.layer.addSublayer(shapeLayer)
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.toValue = 1
animation.duration = 2.0
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
animation.fillMode = CAMediaTimingFillMode.both // keep to value after finishing
animation.isRemovedOnCompletion = false // don't remove after finishing
CATransaction.begin()
CATransaction.setCompletionBlock({
UIView.animate(withDuration: 0.5, animations: {
self.loginButton.alpha = 1.0
})
})
shapeLayer.add(animation, forKey: animation.keyPath)
CATransaction.commit()
}
private func animateLogo(completion: @escaping ()->()) {
UIView.animate(withDuration: 1.0, animations: {
self.logoImageView.frame = self.logoImageView.frame.offsetBy(dx: 0, dy: -250)
}, completion: { _ in
completion()
})
}
@objc private func userTapOnCar() {
if carImageView.frame.origin.x > view.frame.width/2 {
// Destination is on the right, go back to the left
self.animateCarToLeft()
} else {
// Destination is on the left, go back to the right
self.animateCarToRight()
}
}
private func animateCarToRight() {
carAnimator.stopAnimation(true)
carAnimator.addAnimations {
// Move car to the bottom right of the screen
self.carImageView.frame = CGRect(origin: CGPoint(x: self.view.frame.width - self.carSize.width,
y: self.view.frame.height - 100),
size: self.carSize)
}
carAnimator.addCompletion { _ in
UIView.animate(withDuration: 0.5, animations: {
self.carImageView.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
}, completion: { _ in
})
}
carAnimator.startAnimation()
}
private func animateCarToLeft() {
carAnimator.stopAnimation(true)
carAnimator.addAnimations {
// Move car to the bottom left of the screen
self.carImageView.frame = CGRect(origin: CGPoint(x: 0,
y: self.view.frame.height - 100),
size: self.carSize)
}
carAnimator.addCompletion { _ in
UIView.animate(withDuration: 0.5, animations: {
self.carImageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}, completion: { _ in
self.animateCarToRight()
})
}
carAnimator.startAnimation()
}
}
Copy the code