Ich entwickle eine Commerce-Anwendung. Wenn ich einen Artikel zum Warenkorb hinzufüge, möchte ich einen Effekt erstellen, bei dem ein Bild des Artikels einem gekrümmten Pfad folgt und auf der Registerkarte "Warenkorb" landet.
Wie kann ich eine Animation eines Bildes entlang einer solchen Kurve erstellen?
iphone
objective-c
ios
cocoa-touch
core-animation
Maxim Mikheev
quelle
quelle
Antworten:
Um das, was Nikolai gesagt hat, zu erweitern, ist es am besten, die Kernanimation zu verwenden, um die Bewegung des Bildes oder der Ansicht entlang eines Bezier-Pfades zu animieren. Dies wird mithilfe einer CAKeyframeAnimation erreicht. Ich habe beispielsweise den folgenden Code verwendet, um ein Bild einer Ansicht in ein Symbol zu animieren, um das Speichern anzuzeigen (wie im Video für diese Anwendung zu sehen ist ):
Importieren Sie zunächst die QuartzCore-Headerdatei
#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];
quelle
Der Weg zum Animieren entlang CGPath mit
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) }
Datei:
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 } }
Datei :
Math.BezierPath.swift
. Schauen Sie sich diese SO-Antwort an: https://stackoverflow.com/a/50782971/1418981quelle
Sie können die Center-Eigenschaft eines UIView mithilfe einer CAKeyframeAnimation animieren. Siehe das CoreAnimation- Programmierhandbuch.
quelle
Swift 4-Version ähnlich dem ObjC-Beispiel aus der ursprünglichen Antwort.
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") } }
quelle