1

Creating an app where a an image moves upon the press of a button(repeated 3 times). The image currently has a linear movement but what I need is a circular movement animation for it.

The image should start from the left of the screen, go towards top and then to the right of the screen so there are 3 points where the image stops. This has to be done with a circular animation.

enum TimeOfDay: String {
    case Dimineata = "Dimineata"
    case Pranz = "Pranz"
    case Seara = "Seara"
}

class ViewController: UIViewController {
    @IBOutlet weak var timeOfDayLabel: UILabel!
    @IBOutlet weak var sunImage: UIImageView!

    var timeOfDay = TimeOfDay.Dimineata

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func didTapNext(_ sender: Any) {
        switch timeOfDay {
        case .Dimineata:
            timeOfDay = .Pranz
            sunImage.image = UIImage(named: "LunchSun")

            UIView.animate(withDuration: 1) {
                self.sunImage.frame = CGRect(x: self.view.center.x-50, y: 120, width: 100, height: 100)
            }
        case .Pranz:
            timeOfDay = .Seara
            sunImage.image = UIImage(named: "NightSun")
            UIView.animate(withDuration: 1) {
                self.sunImage.frame = CGRect(x: self.view.frame.width-50, y: 166, width: 100, height: 100)
            }
        default:
            timeOfDay = .Dimineata
            sunImage.image = UIImage(named: "NightSun")
            UIView.animate(withDuration: 1) {
                self.sunImage.frame = CGRect(x: self.view.frame.origin.x-50, y: 166, width: 100, height: 100)
            }
        }
        timeOfDayLabel.text = timeOfDay.rawValue.uppercased()
    }

}
Jacob
  • 77,566
  • 24
  • 149
  • 228
  • Basically https://stackoverflow.com/questions/2555614/uiview-animation-along-a-round-path - create a path and an corresponding animation. – luk2302 Sep 24 '18 at 18:32
  • Same as https://stackoverflow.com/questions/42158323/cakeyframeanimation-not-linear-for-values-greater-than-pi Put the sun on the end of an invisible arm and rotate the arm like the hands of a clock. – matt Sep 25 '18 at 10:08

1 Answers1

2
  • Create a circular path
  • Create a CAKeyframeAnimation
  • Set the animation.path to the circular path
  • Add that animation to the layer of the image view
  • Set the frame of image view to the last point in the path

Example code:

var imageView : UIImageView!
// Adapt these constants to your case
let initialX: CGFloat = 40    
let imageViewWidth: CGFloat = 60

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    imageView = UIImageView()
    imageView.backgroundColor = .red
    imageView.frame = CGRect(x: initialX,
                             y: view.frame.height / 2.0 - 20,
                             width: 60,
                             height: 40)
    imageView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(imageView)

}

@IBAction func animate(_ sender: Any) {

    //You can customize this path
    let circularPath = UIBezierPath(arcCenter: view.center,
                                  radius: view.frame.width / 2 - initialX - imageViewWidth / 2,
                                  startAngle: -.pi,
                                  endAngle: 0,
                                  clockwise: true)

    //Create the animation
    let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
    animation.duration = 2  // In seconds
    animation.repeatCount = 1 //At maximum it could be MAXFLOAT if you want the animation to seem to loop forever
    animation.path = circularPath.cgPath
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)  //Optional

    //Add the animation to the layer of the image view
    imageView.layer.add(animation, forKey: "myAnimation")

    //prevent the imageView from going back to its original coordinates
    imageView.frame.origin.x = circularPath.cgPath.currentPoint.x - imageView.frame.width / 2
    imageView.frame.origin.y = circularPath.cgPath.currentPoint.y - imageView.frame.height / 2
}
ielyamani
  • 17,807
  • 10
  • 55
  • 90
  • thank you ! this worked in the end but i'm having two issues: 1. The image goes back to its original coordinates after the animation ends(i'm using the last line of code where you clearly specify that it is made to avoid this) 2. So the animation starts from left, goes up (where it has to stop) and then goes to the right side(where it has to stop as well), creating a semi circle.However, the animation goes directly from left to right. Should I create separate animations to achieve my goals or pause/resume the animation somehow? – Robert Cristian Sep 26 '18 at 11:56
  • The code above gives a half circle animation. You could adjust it to be a quarter of a circle by adjusting the `startAngle` and `endAngle`. – ielyamani Sep 26 '18 at 12:02
  • For you, you'll have to have three animations: `Dimineata` to `Pranz`, `Pranz` to `Seara`, and `Seara` back to `Dimineata` – ielyamani Sep 26 '18 at 12:13
  • If this answer solved your problem please mark it as accepted by clicking the check mark next to the answer, ora/and upvote it. see: [How does accepting an answer work?](https://meta.stackexchange.com/a/5235) for more information – ielyamani Sep 26 '18 at 12:14