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

UIImageView 中的 UIImage 位置偏移

以全尺寸保存 UIImage,包括从 UIImageView 进行的转换

UIImageView,从远程 URL 加载 UIImage

如何在 UIImageView 中显示 UIImage?