मैं घुमावदार रास्ते के साथ किसी दृश्य या छवि की गति को कैसे तय कर सकता हूं?


80

मैं एक कॉमर्स एप्लिकेशन विकसित कर रहा हूं। जब मैं खरीदारी कार्ट में एक आइटम जोड़ता हूं, तो मैं एक प्रभाव बनाना चाहता हूं जहां आइटम की एक छवि घुमावदार पथ का अनुसरण करती है और कार्ट टैब पर समाप्त होती है।

मैं इस तरह एक वक्र के साथ एक छवि का एनीमेशन कैसे बना सकता हूं?


IPhone पर एनिमेटेड छवियाँ इस लिंक को देखें। यह निश्चित रूप से आपकी मदद करेगा। धन्यवाद।
सालमन

जवाबों:


153

निकोलाई ने जो कहा, उसका विस्तार करने के लिए, इसे संभालने का सबसे अच्छा तरीका कोर एनिमेशन का उपयोग करना है, जो बेजियर पथ के साथ छवि या दृश्य की गति को चेतन करता है। यह CAKeyframeAnimation का उपयोग करके पूरा किया गया है। उदाहरण के लिए, मैंने सहेजने का संकेत देने के लिए एक आइकन में एक दृश्य की छवि को चेतन करने के लिए निम्नलिखित कोड का उपयोग किया है (जैसा कि इस एप्लिकेशन के लिए वीडियो में देखा जा सकता है ):

सबसे पहले क्वार्ट्जकोर हेडर फ़ाइल आयात करें #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 start
CGPoint 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 effect
CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[fadeOutAnimation setToValue:[NSNumber numberWithFloat:0.3]];
fadeOutAnimation.fillMode = kCAFillModeForwards;
fadeOutAnimation.removedOnCompletion = NO;

// Set up scaling
CABasicAnimation *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 movement
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
//Setting Endpoint of the animation
CGPoint 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];

मुझे यह मिल गया है। लेकिन मैं एनीमेशन प्रभाव बनाना चाहता हूं जैसे कि मैं बड़ी छवि रखता हूं मुझे छवि को बड़ी छवि के केंद्र में बदलना चाहिए, फिर एनीमेशन पथ जोड़ना चाहिए। इसे कैसे प्राप्त करें।

मुझे यकीन नहीं है कि आप क्या पूछ रहे हैं, लेकिन ऊपर दिए गए एनीमेशन में तीन चीजें हैं: एक घुमावदार रास्ते के साथ छवि को स्थानांतरित करता है, इसे सिकुड़ता है क्योंकि यह चलता है ताकि यह तब तक छोटा हो जब तक यह अंत बिंदु को हिट नहीं करता है, और इसे बाहर निकालता है यह चलता है। आप आवश्यकतानुसार या मानों को बदलकर आकार बदल सकते हैं।
ब्रैड लार्सन

मुझे क्या शामिल करना होगा ताकि Xcode सभी CAKey ... सामान को पहचान सके? यह कहता है कि यह प्रतीकों को नहीं ढूंढता है।
धन्यवाद

2
आपको शामिल करने की आवश्यकता है कि आप हमेशा कोर एनिमेशन, क्वार्ट्जकोर / क्वार्ट्जकोर.एच, और क्वार्ट्जकोर फ्रेमवर्क के खिलाफ लिंक क्या करते हैं।
ब्रैड लार्सन

वह उपाय था। उत्तम!
धन्यवाद

4

CGPath के साथ चेतन का रास्ता UIView.animateKeyframes(स्विफ्ट 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)
}

फ़ाइल: Math.Easing.swift

// Inspired by: RBBAnimation/RBBEasingFunction.m: https://github.com/robb/RBBAnimation/blob/master/RBBAnimation/RBBEasingFunction.m
extension 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
   }
}

फ़ाइल: Math.BezierPath.swift। इस SO उत्तर को देखें: https://stackoverflow.com/a/50782971/1418981

यहाँ छवि विवरण दर्ज करें


2

आप CAKeyframeAnimation का उपयोग करके एक UIView की केंद्र संपत्ति को चेतन कर सकते हैं। CoreAnimation प्रोग्रामिंग गाइड देखें ।


0

मूल प्रतिक्रिया से ObjC उदाहरण के समान स्विफ्ट 4 संस्करण।

class KeyFrameAnimationsViewController: ViewController {

   let sampleImage = ImageFactory.image(size: CGSize(width: 160, height: 120), fillColor: .blue)

   private lazy var imageView = ImageView(image: sampleImage)
   private lazy var actionButton = Button(title: "Animate").autolayoutView()

   override func setupUI() {
      view.addSubviews(imageView, actionButton)
      view.backgroundColor = .gray
   }

   override func setupLayout() {
      LayoutConstraint.withFormat("|-[*]", actionButton).activate()
      LayoutConstraint.withFormat("V:|-[*]", actionButton).activate()
   }

   override func setupHandlers() {
      actionButton.setTouchUpInsideHandler { [weak self] in
         self?.animate()
      }
   }

   private func animate() {

      imageView.alpha = 1
      let isRemovedOnCompletion = false

      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)

      imageView.frame = CGRect(origin: originFrom, size: sizeFrom)
      imageView.layer.position = originFrom

      // Set up fade out effect
      let fadeOutAnimation = CABasicAnimation(keyPath: "opacity")
      fadeOutAnimation.toValue = 0.3
      fadeOutAnimation.fillMode = kCAFillModeForwards
      fadeOutAnimation.isRemovedOnCompletion = isRemovedOnCompletion

      // Set up scaling
      let resizeAnimation = CABasicAnimation(keyPath: "bounds.size")
      resizeAnimation.toValue = sizeTo
      resizeAnimation.fillMode = kCAFillModeForwards
      resizeAnimation.isRemovedOnCompletion = isRemovedOnCompletion

      // Set up path movement
      let pathAnimation = CAKeyframeAnimation(keyPath: "position")
      pathAnimation.calculationMode = kCAAnimationPaced;
      pathAnimation.fillMode = kCAFillModeForwards;
      pathAnimation.isRemovedOnCompletion = isRemovedOnCompletion

      // Setting Endpoint of the animation to end animation in last tab use
      let curvedPath = CGMutablePath()
      curvedPath.move(to: originFrom)
      // About curves: https://www.bignerdranch.com/blog/core-graphics-part-4-a-path-a-path/
      curvedPath.addQuadCurve(to: originTo, control: CGPoint(x: originFrom.x,  y: originTo.y))
      pathAnimation.path = curvedPath

      let group = CAAnimationGroup()
      group.fillMode = kCAFillModeForwards
      group.isRemovedOnCompletion = isRemovedOnCompletion
      group.animations = [fadeOutAnimation, pathAnimation, resizeAnimation]
      group.duration = 0.7
      group.setValue(imageView, forKey: "imageViewBeingAnimated")

      imageView.layer.add(group, forKey: "savingAnimation")
   }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.