在不同时间动画改变高度和宽度

Animate Change Height and Width at Different Times

我有一张正在制作动画的图片,目的是让它看起来像 "breathing"。

目前,我使用下面的代码让图像以一种体面的方式移动:(我正在制作一个包含几个 UIImageView 的 UIView 的动画,它们都作为一个整体移动)

- (IBAction)animateButton:(id)sender {


    [UIView animateWithDuration:0.64
                          delay:0
                        options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
                     animations:^{
                         _testView.transform = CGAffineTransformMakeScale(1.08f, 1.02f);

                     } completion:nil];

}

但是,我似乎无法弄清楚如何以与 y 不同的速率在 x 中动画拉伸图像。这样做的目的是让图像看起来好像真的是活的,而不是在一个清晰的重复动作中循环。

我尝试将 UIView 的中心锚定到特定位置,然后通过一个让我们说 1.0 秒的动画为宽度添加一些数字。 然后我尝试同时调用另一个动画,该动画仅在高度上执行相同的动画,但添加了不同的量,持续约 1.3 秒。但是我无法让这两个同时执行,因为一个会优先于另一个。

如果有人能引导我在正确的方向上以不同的速率对宽度和高度的重复拉伸进行动画处理,我将不胜感激。谢谢!

考虑两个时间重叠的变化如下所示:

        |---- change x ---|
   |---- change y ----|

如果两个间隔是任意且重叠的,则可以用三个动画来表示:一个单独改变一个维度,一个同时改变两个维度,另一个单独改变一个维度。

您可以看到有多种方法可以指定它,但让我们尝试一种直接的方法。为了避免复合尺度的算法,让我们指定一个维度、一个像素变化和一个持续时间。例如...

@[ @{@"dimension":@"width", @"delta":@10, @"duration":0.2},
   @{@"dimension":@"both", @"delta":@40, @"duration":0.8}, 
   @{@"dimension":@"width", @"delta":@10, @"duration":0.2} ]

... 表示宽度的较长变化跨越较短的高度变化。你可以看到这是一种非常完整的语言,可以完成你想要的事情。

我们需要一个动画方法来连续执行更改。一种简单的方法是将操作数组视为待办事项列表。递归算法说:要做一系列事情,做第一个,然后做其余的....

- (void)animateView:(UIView *)view actions:(NSArray *)actions completion:(void (^)(BOOL))completion {
    if (actions.count == 0) return completion(YES);
    NSDictionary *action = actions[0];
    NSArray *remainingActions = [actions subarrayWithRange:NSMakeRange(1, actions.count-1)];
    [self animateView:view action:action completion:^(BOOL finished) {
        [self animateView:view actions:remainingActions completion:completion];
    }];
}

对于动画,您可能希望对中间动画使用线性时序曲线,但我可以看到您变得更加精细并更改了列表开始和末尾的时序曲线。

- (void)animateView:(UIView *)view action:(NSDictionary *)action completion:(void (^)(BOOL))completion {
    NSString *dimension = action[@"dimension"];
    CGFloat delta = [action[@"delta"] floatValue];
    NSTimeInterval duration = [action[@"duration"] floatValue];

    CGRect frame = view.frame;

    if ([dimension isEqualToString:@"width"]) {
        frame = CGRectInset(frame, -delta, 0);
    } else if ([dimension isEqualToString:@"height"]) {
        frame = CGRectInset(frame, 0, -delta);
    } else {
        frame = CGRectInset(frame, -delta, -delta);
    }
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        view.frame = frame;
    } completion:completion];
}

如果字典数组太笨拙而无法指定(而且它相当通用),您可以在顶部添加一些方便的方法,为调用者提供一些更简单的方案并构建更通用表示的数组。