import UIKit
class AnimatedCircleViewController: UIViewController {
let circleView = UIView()
let animateButton = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
circleView.backgroundColor = .systemBlue
circleView.frame = CGRect(x: 40, y: view.bounds.midY - 25, width: 50, height: 50)
circleView.layer.cornerRadius = 25
view.addSubview(circleView)
animateButton.setTitle("Animate", for: .normal)
animateButton.frame = CGRect(x: 0, y: view.bounds.height - 80, width: 120, height: 44)
animateButton.center.x = view.center.x
animateButton.addTarget(self, action: #selector(animateCircle), for: .touchUpInside)
view.addSubview(animateButton)
}
@objc func animateCircle() {
let endX = view.bounds.width - 90 // 40 padding + 50 width
let timingParameters = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.68, y: -0.55), controlPoint2: CGPoint(x: 0.27, y: 1.55))
let animator = UIViewPropertyAnimator(duration: 2.0, timingParameters: timingParameters)
animator.addAnimations {
self.circleView.frame.origin.x = endX
}
animator.startAnimation()
}
}We use UIViewPropertyAnimator to create an animation with a custom cubic Bezier timing curve. This curve is defined by two control points that shape the speed of the animation, making it non-linear and more dynamic than standard ease-in or ease-out.
The circle starts near the left side and moves horizontally to the right side over 2 seconds. The animateCircle() method triggers this animation when the button is tapped.
This approach gives you fine control over the animation timing, making the movement feel more natural or playful depending on the curve.