- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
下面是想要实现的动画效果:
接下来就剩下🚗。的动画了。
首先需要把🚗。的图片放到Asset里面。
同样的声明一个carImageView属性和期望的图片大小属性,这里需要多创建一个carAnimator来实现动画。
private let carSize = CGSize(width: 50, height: 45)
private var carImageView: UIImageView!
private var carAnimator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: 3.0, curve: .easeInOut, animations: nil)
同样的,这里需要在setupUI里面设置好carImageView的大小以及其他属性,然后设为可以互动,添加点击手势以及响应方法以便后面添加点击的动画,最后添加为视图的子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)
声明一个animateCarToRight方法,在里面先添加一个🚗。从左边移动到右边的动画,然后完成移动的动画后执行一个左右翻转的动画,并将其添加到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()
}
接下来在carImageView的点击响应方法里面添加判断carImageView.frame.origin.x 和view.frame.width/2的代码,如果大于则需要从右到左移动,小于则是从左到右移动。
@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()
}
}
这里还需要添加animateCarToLeft方法,这里和animateCarToRight方法差不多,只是修改需要移动的x值和翻转的transform的值就可以了。
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()
}
到这里登陆页面动画就完成啦。 完整代码:
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()
}
}