UIImage 从一个 UIImageView 移动到另一个 UIImageView 的动画
Posted
技术标签:
【中文标题】UIImage 从一个 UIImageView 移动到另一个 UIImageView 的动画【英文标题】:Animation of a UIImage moving from one UIImageView to another 【发布时间】:2012-03-18 18:35:08 【问题描述】:我已经设法使用 [UIView animateWithDuration... 来完成我在 UI 中需要的动画。现在我想沿着弯曲的路径移动图像,整个 CAAnimation 集群对我来说看起来非常令人生畏。
如果有人能帮我填写我希望我能编码的方法,我将非常感激,它看起来像这样:
- (void)makeAnImageFlyFrom:(UIImageView *)imageViewA to:(UIImageView *)imageViewB alongPath:(CGMutablePathRef)path duration:(NSTimeInterval)duration
UIImage *imageToFly = imageViewA.image;
// magic, that i'm too lazy to learn right now goes here
// image flys along the path and gets scaled to match imageViewB.
// then view/layer hierarchy is just as it was, but imageViewB has a new image
// maybe this happens on animationDidStop...
imageViewB.image = imageToFly;
如果您认为这种方法有更智能的界面,请随意替换参数(如路径引用)。提前致谢。
【问题讨论】:
这几乎是构建 CAKeyframeAnimation 所需的信息,q.v。 developer.apple.com/library/mac/#documentation/GraphicsImaging/… bill.dudney.net/roller/objc/entry/keyframe_animation 我认为我现在得到的半页破碎的东西会更难回答(并且由于我的错误而将答案发送到错误的方向)然后要求一个干净的石板。在我看来,这似乎是一个特定的操作,有更多经验的人会很容易掌握他们的技巧。 CAAnimation、CALayer、CAAnimationGroup、CATimingFunction、CGPath 等是移动图像的一个相当大的学习曲线。是否有一个明显的答案,任何 rube 都应该花点时间想出答案?把它放在一个侮辱我的答案中,我会把它标记为正确的。 【参考方案1】:好的,整个星期天之后,我认为这是一种可行的方法。我仍然不清楚一些东西,在 cmets 中注明,但如果你需要这种类型的东西,请随意剪切和粘贴。我保证不会叫你懒惰:
- (void)makeAnImageFlyFrom:(UIImageView *)imageViewA to:(UIImageView *)imageViewB duration:(NSTimeInterval)duration
// it's simpler but less general to not pass in the path. i chose simpler because
// there's a lot of geometry work using the imageView frames here anyway.
UIImageView *animationView = [[UIImageView alloc] initWithImage:imageViewA.image];
animationView.tag = kANIMATION_IMAGE_TAG;
animationView.frame = imageViewA.frame;
[self addSubview:animationView];
// scale
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
[resizeAnimation setFromValue:[NSValue valueWithCGSize:imageViewA.bounds.size]];
[resizeAnimation setToValue:[NSValue valueWithCGSize:imageViewB.bounds.size]];
// build the path
CGRect aRect = [imageViewA convertRect:imageViewA.bounds toView:self];
CGRect bRect = [imageViewB convertRect:imageViewB.bounds toView:self];
// unclear why i'm doing this, but the rects converted to this view's
// coordinate system seemed have origin's offset negatively by half their size
CGFloat startX = aRect.origin.x + aRect.size.width / 2.0;
CGFloat startY = aRect.origin.y + aRect.size.height / 2.0;
CGFloat endX = bRect.origin.x + bRect.size.width / 2.0;
CGFloat endY = bRect.origin.y + bRect.size.height / 2.0;
CGFloat deltaX = endX - startX;
CGFloat deltaY = endY - startY;
// these control points suited the path i needed. your results may vary
CGFloat cp0X = startX + 0.3*deltaX;
CGFloat cp0Y = startY - 1.3*deltaY;
CGFloat cp1X = endX + 0.1*deltaX;
CGFloat cp1Y = endY - 0.5*deltaY;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, startX, startY);
CGPathAddCurveToPoint(path, NULL, cp0X, cp0Y, cp1X, cp1Y, endX, endY);
// keyframe animation
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
keyframeAnimation.calculationMode = kCAAnimationPaced;
keyframeAnimation.fillMode = kCAFillModeForwards;
keyframeAnimation.removedOnCompletion = NO;
keyframeAnimation.path = path;
// assuming i need to manually release, despite ARC, but not sure
CGPathRelease(path);
// a little unclear about the fillMode, but it works
// also unclear about removeOnCompletion, because I remove the animationView
// but that seems to be insufficient
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[group setAnimations:[NSArray arrayWithObjects:keyframeAnimation, resizeAnimation, nil]];
group.duration = duration;
group.delegate = self;
// unclear about what i'm naming with the keys here, and why
[group setValue:animationView forKey:@"animationView"];
[animationView.layer addAnimation:group forKey:@"animationGroup"];
// clean up after like this
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
UIImageView *imageViewForAnimation = (UIImageView *)[self viewWithTag:kANIMATION_IMAGE_TAG];
// get the imageView passed to the animation as the destination
UIImageView *imageViewB = (UIImageView *)[self viewWithTag:kDEST_TAG];
imageViewB.image = imageViewForAnimation.image;
[imageViewForAnimation removeFromSuperview];
【讨论】:
天哪!真的很有帮助的家伙..谁告诉你是懒惰的!..只是 1 混乱..你在哪里添加 kDEST_TAG? 谢谢。它只是一个 int 标签的#define。将其分配给您希望图像飞行的图像视图:#define kDEST_TAG 128 然后 imageViewDestination.tag = kDEST_TAG。 从那时起我对这段代码进行了一些改进。让我知道您是否需要帮助或变体,我会提供。 这是我的最新资料pastebin.com/FZXvRDS2。新界面允许您指定一个矩形目标(而不是 imageView)和一个在完成时调用的块。然后,在块中,您可以将图像分配给另一个 UIImageView,或者做任何您想做的事情。它还可以更好地计算动画的路径。 @MilKyWaY - 我不得不从我的项目中调整该代码以使其对您更通用。这导致我犯了一个错误。在该粘贴箱中的第 10 行之前,添加行 self.animationParent = parent;以上是关于UIImage 从一个 UIImageView 移动到另一个 UIImageView 的动画的主要内容,如果未能解决你的问题,请参考以下文章
UIImage 从一个 UIImageView 移动到另一个 UIImageView 的动画
UIImageView 不显示从通知中获取的 UIImage
以全尺寸保存 UIImage,包括从 UIImageView 进行的转换