How can I animate the movement of a view or image along a curved path? How can I animate the movement of a view or image along a curved path? ios ios

How can I animate the movement of a view or image along a curved path?


To expand upon what Nikolai said, the best way to handle this is to use Core Animation to animate the motion of the image or view along a Bezier path. This is accomplished using a CAKeyframeAnimation. For example, I've used the following code to animate an image of a view into an icon to indicate saving (as can be seen in the video for this application):

First of all import QuartzCore header file#import <QuartzCore/QuartzCore.h>

UIImageView *imageViewForAnimation = [[UIImageView alloc] initWithImage:imageToAnimate];imageViewForAnimation.alpha = 1.0f;CGRect imageFrame = imageViewForAnimation.frame;//Your image frame.origin from where the animation need to get startCGPoint viewOrigin = imageViewForAnimation.frame.origin;viewOrigin.y = viewOrigin.y + imageFrame.size.height / 2.0f;viewOrigin.x = viewOrigin.x + imageFrame.size.width / 2.0f;imageViewForAnimation.frame = imageFrame;imageViewForAnimation.layer.position = viewOrigin;[self.view addSubview:imageViewForAnimation];// Set up fade out effectCABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];[fadeOutAnimation setToValue:[NSNumber numberWithFloat:0.3]];fadeOutAnimation.fillMode = kCAFillModeForwards;fadeOutAnimation.removedOnCompletion = NO;// Set up scalingCABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(40.0f, imageFrame.size.height * (40.0f / imageFrame.size.width))]];resizeAnimation.fillMode = kCAFillModeForwards;resizeAnimation.removedOnCompletion = NO;// Set up path movementCAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];pathAnimation.calculationMode = kCAAnimationPaced;pathAnimation.fillMode = kCAFillModeForwards;pathAnimation.removedOnCompletion = NO;//Setting Endpoint of the animationCGPoint endPoint = CGPointMake(480.0f - 30.0f, 40.0f);//to end animation in last tab use //CGPoint endPoint = CGPointMake( 320-40.0f, 480.0f);CGMutablePathRef curvedPath = CGPathCreateMutable();CGPathMoveToPoint(curvedPath, NULL, viewOrigin.x, viewOrigin.y);CGPathAddCurveToPoint(curvedPath, NULL, endPoint.x, viewOrigin.y, endPoint.x, viewOrigin.y, endPoint.x, endPoint.y);pathAnimation.path = curvedPath;CGPathRelease(curvedPath);CAAnimationGroup *group = [CAAnimationGroup animation]; group.fillMode = kCAFillModeForwards;group.removedOnCompletion = NO;[group setAnimations:[NSArray arrayWithObjects:fadeOutAnimation, pathAnimation, resizeAnimation, nil]];group.duration = 0.7f;group.delegate = self;[group setValue:imageViewForAnimation forKey:@"imageViewBeingAnimated"];[imageViewForAnimation.layer addAnimation:group forKey:@"savingAnimation"];[imageViewForAnimation release];


The way to animate along CGPath using UIView.animateKeyframes (Swift 4)

private func animateNew() {   let alphaFrom: CGFloat = 1   let alphaTo: CGFloat = 0.3   let sizeFrom = CGSize(width: 40, height: 20)   let sizeTo = CGSize(width: 80, height: 60)   let originFrom = CGPoint(x: 40, y: 40)   let originTo = CGPoint(x: 240, y: 480)   let deltaWidth = sizeTo.width - sizeFrom.width   let deltaHeight = sizeTo.height - sizeFrom.height   let deltaAlpha = alphaTo - alphaFrom   // Setting default values   imageViewNew.alpha = alphaFrom   imageViewNew.frame = CGRect(origin: originFrom, size: sizeFrom)   // CGPath setup for calculating points on curve.   let curvedPath = CGMutablePath()   curvedPath.move(to: originFrom)   curvedPath.addQuadCurve(to: originTo, control: CGPoint(x: originFrom.x,  y: originTo.y))   let path = Math.BezierPath(cgPath: curvedPath, approximationIterations: 10)   // Calculating timing parameters   let duration: TimeInterval = 0.7   let numberOfKeyFrames = 16   let curvePoints = Math.Easing.timing(numberOfSteps: numberOfKeyFrames, .easeOutQuad)   UIView.animateKeyframes(withDuration: duration, delay: 0, options: [.calculationModeCubic], animations: {      // Iterating curve points and adding key frames      for point in curvePoints {         let origin = path.point(atPercentOfLength: point.end)         let size = CGSize(width: sizeFrom.width + deltaWidth * point.end,                           height: sizeFrom.height + deltaHeight * point.end)         let alpha = alphaFrom + deltaAlpha * point.end         UIView.addKeyframe(withRelativeStartTime: TimeInterval(point.start), relativeDuration: TimeInterval(point.duration)) {            self.imageViewNew.frame = CGRect(origin: origin, size: size)            self.imageViewNew.alpha = alpha         }      }   }, completion: nil)}

File: Math.Easing.swift

// Inspired by: RBBAnimation/RBBEasingFunction.m: https://github.com/robb/RBBAnimation/blob/master/RBBAnimation/RBBEasingFunction.mextension Math { public struct Easing { } }extension Math.Easing {   public enum Algorithm: Int {      case linear, easeInQuad, easeOutQuad, easeInOutQuad   }   @inline(__always)   public static func linear(_ t: CGFloat) -> CGFloat {      return t   }   @inline(__always)   public static func easeInQuad(_ t: CGFloat) -> CGFloat  {      return t * t   }   @inline(__always)   public static func easeOutQuad(_ t: CGFloat) -> CGFloat  {      return t * (2 - t)   }   @inline(__always)   public static func easeInOutQuad(_ t: CGFloat) -> CGFloat  {      if t < 0.5 {         return 2 * t * t      } else {         return -1 + (4 - 2 * t) * t      }   }}extension Math.Easing {   public struct Timing {      public let start: CGFloat      public let end: CGFloat      public let duration: CGFloat      init(start: CGFloat, end: CGFloat) {         self.start = start         self.end = end         self.duration = end - start      }      public func multiplying(by: CGFloat) -> Timing {         return Timing(start: start * by, end: end * by)      }   }   public static func process(_ t: CGFloat, _ algorithm: Algorithm) -> CGFloat {      switch algorithm {      case .linear:         return linear(t)      case .easeInQuad:         return easeInQuad(t)      case .easeOutQuad:         return easeOutQuad(t)      case .easeInOutQuad:         return easeInOutQuad(t)      }   }   public static func timing(numberOfSteps: Int, _ algorithm: Algorithm) -> [Timing] {      var result: [Timing] = []      let linearStepSize = 1 / CGFloat(numberOfSteps)      for step in (0 ..< numberOfSteps).reversed() {         let linearValue = CGFloat(step) * linearStepSize         let processedValue = process(linearValue, algorithm) // Always in range 0 ... 1         let lastValue = result.last?.start ?? 1         result.append(Timing(start: processedValue, end: lastValue))      }      result = result.reversed()      return result   }}

File: Math.BezierPath.swift. Look on this SO answer: https://stackoverflow.com/a/50782971/1418981

enter image description here


You can animate a UIView's center property using a CAKeyframeAnimation. See the CoreAnimation programming guide.