Анимирайте промяна на височината и ширината в различно време

Имам изображение, което анимирам, за да изглежда така, сякаш "диша".

В момента изображението се движи по приличен начин със следния код по-долу: (Анимирам UIView, който съдържа няколко UIImageView, които всички се движат като едно)

- (IBAction)animateButton:(id)sender {


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

                     } completion:nil];

}

ОБАЧЕ, изглежда не мога да разбера как да анимирам разтягане на изображението в x с различна скорост от y. Смисълът на това е да изглежда така, сякаш изображението действително е живо, без да изглежда, че циклично преминава през ясно повтарящо се движение.

Опитах се, като се опитах да закотвя центъра на UIView към конкретно място, след което добавих някакво число към ширината чрез анимация от да кажем 1,0 секунди. След това се опитах едновременно да извикам друга анимация, която прави същата анимация само до височината, с добавено различно количество, за около 1,3 секунди. Не можах обаче да накарам тези двама да се представят едновременно, тъй като единият щеше да има предимство пред другия.

Ако някой може да ме насочи в правилната посока за анимиране на повтарящо се разтягане на ширината и височината с различни скорости, ще съм много благодарен. Благодаря!


person Will Von Ullrich    schedule 19.09.2015    source източник


Отговори (1)


Помислете, че две промени, припокриващи се във времето, изглеждат така:

        |---- 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];
}

Ако масивът от речници е твърде тромав за определяне (и е доста общ), можете да добавите някои удобни методи отгоре, които предоставят някаква по-проста схема на повикващия и изграждат масива с по-общо представяне.

person danh    schedule 20.09.2015
comment
благодаря ви за задълбочения отговор - месих се в теории като тази, но имах проблеми с точното им изпълнение. надявам се, че в крайна сметка това ще ме отведе в правилната посока. - person Will Von Ullrich; 21.09.2015
comment
Ако бях аз, щях да сложа това в собствен малък проект (или поне да е собствен изглед контролер в текущия ви проект) и просто да се забавлявам с комбинации. Първоначално бих използвал много дълги продължителности, за да мога да видя какво се случва. - person danh; 21.09.2015