class AnimationsTestViewController: UIViewController { enum AnimationPosiXDirection { case left, center, right } enum AnimationFlipDirection { case yAxis, center, xAxis } private let containerView: UIView = { let view = UIView(frame: .zero) view.backgroundColor = .white view.layer.cornerRadius = 16 view.layer.borderWidth = 1.0 view.layer.borderColor = UIColor.lightGray.cgColor view.translatesAutoresizingMaskIntoConstraints = false return view }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .black configureContentView() } private func configureContentView() { view.addSubview(containerView) NSLayoutConstraint.activate([ containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor), containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor), containerView.widthAnchor.constraint(equalToConstant: 200), containerView.heightAnchor.constraint(equalToConstant: 170) ]) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) animateRotate3DFlip(from: .right, direction: .xAxis, rotationCount: 3) } private func animateRotate3DFlip(from: AnimationPosiXDirection, direction: AnimationFlipDirection, centerLeftToRight: Bool = false, rotationCount: CGFloat = 1) { prepareScale3DAnimation(from: from) start3DFlipAnimationWith(direction: direction, centerLeftToRight: centerLeftToRight, rotationCount: rotationCount) } private func prepareScale3DAnimation(from: AnimationPosiXDirection) { var perspective = CATransform3DIdentity switch from { case .left: perspective.m34 = 1 / -200 case .center: perspective.m34 = 0 / -200 case .right: perspective.m34 = -1 / -200 } containerView.layer.transform = perspective } private func start3DFlipAnimationWith(direction: AnimationFlipDirection, centerLeftToRight: Bool = false, rotationCount: CGFloat = 1) { var rotateAnimation: CABasicAnimation! switch direction { case .xAxis: rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.y") case .center: rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z") case .yAxis: rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.x") } rotateAnimation.fromValue = 0 let directionAndTimes = CGFloat.pi * rotationCount rotateAnimation.byValue = centerLeftToRight ? directionAndTimes : -directionAndTimes rotateAnimation.duration = 1 rotateAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // add animation containerView.layer.add(rotateAnimation, forKey: "3Dflip") } }