阅读 330

Swift动画 —— 登陆页面动画(三)

下面是想要实现的动画效果: 在这里插入图片描述 接下来就剩下🚗。的动画了。 首先需要把🚗。的图片放到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()
    }
}
复制代码
文章分类
iOS
文章标签