Подтвердить что ты не робот

Как reset/перезапустить анимацию и постоянно ли она отображаться?

Итак, я довольно новичок в программировании на iOS и унаследовал проект от бывшего сотрудника. Мы создаем приложение, содержащее пользовательский интерфейс калибровки. Когда поступают данные, мы хотим плавно поворачивать наш "слой" (изображение иглы) от текущего угла до нового целевого угла. Вот что мы имеем, что хорошо работало с медленными данными:

-(void) MoveNeedleToAngle:(float) target
{
   static float old_Value = 0.0;
   CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation");
   [rotateCurrentPressureTick setDelegate:self];
   rotateCurrentPressureTick.fromValue = [NSSNumber numberWithFloat:old_value/57.2958];
   rotateCurrentPressureTick.removedOnCompletion=NO;
   rotateCurrentPressureTick.fillMode=kCAFillModeForwards;
   rotateCurrentPressureTick.toValue=[NSSNumber numberWithFloat:target/57.2958];
   rotateCurrentPressureTick.duration=3; // constant 3 second sweep

   [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"];
   old_Value = target;
}

Проблема заключается в том, что у нас есть новая схема данных, в которой новые данные могут появляться (и указанный выше метод) быстрее, прежде чем анимация будет завершена. Что происходит, я думаю, что анимация перезапускается со старой цели на новую цель, что делает ее очень нервной.

Итак, мне было интересно, как изменить приведенную выше функцию для добавления непрерывного/перезапускаемого поведения, как показано ниже:

  • Проверьте, выполняется ли текущая анимация и
  • Если да, укажите, где находится текущий угол анимации, а затем
  • Отмените текущий и запустите новую анимацию от текущего вращения до нового целевого вращения.

Можно ли построить это поведение в указанной выше функции?

Спасибо. Извините, если вопрос кажется неосведомленным, я изучил и понял вышеуказанные объекты/методы, но не эксперт.

4b9b3361

Ответ 1

Да, вы можете сделать это, используя свой существующий метод, если вы добавите этот бит магии:

    - (void)removeAnimationsFromView:(UIView*)view {
        CALayer *layer = view.layer.presentationLayer;
        CGAffineTransform transform = layer.affineTransform;
        [layer removeAllAnimations];
        view.transform = transform;
    }

Уровень презентации инкапсулирует фактическое состояние анимации. Само представление не несет свойств состояния анимации, в основном, когда вы устанавливаете конечное состояние анимации, представление приобретает это состояние, как только вы запускаете анимацию. Это слой презентации, который вы видите во время анимации.

Этот метод фиксирует состояние уровня представления в тот момент, когда вы отменяете анимацию, а затем применяет это состояние к виду.

Теперь вы можете использовать этот метод в своем методе анимации, который будет выглядеть примерно так:

-(void) MoveNeedleToAngle:(float) target{
    [self removeAnimationsFromView:imageView_Needle];
    id rotation = [imageView_Needle valueForKeyPath:@"layer.transform.rotation.z"];
    CGFloat old_value = [rotation floatValue]*57.2958;

   // static float old_value = 0.0;
    CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    [rotateCurrentPressureTick setDelegate:self];
    rotateCurrentPressureTick.fromValue = [NSNumber numberWithFloat:old_value/57.2958];
    rotateCurrentPressureTick.removedOnCompletion=NO;
    rotateCurrentPressureTick.fillMode=kCAFillModeForwards;
    rotateCurrentPressureTick.toValue=[NSNumber numberWithFloat:target/57.2958];
    rotateCurrentPressureTick.duration=3; // constant 3 second sweep

    [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"];

    old_value = target;

}

(Я внес минимальные изменения в ваш метод: есть несколько изменений стиля кодирования, которые я бы тоже сделал, но они не имеют отношения к вашей проблеме)

Кстати, я предлагаю вам прокормить ваш метод в радианах, а не в градусах, что будет означать, что вы можете удалить эти 57.2958 константы.

Ответ 2

Вы можете получить текущее вращение из уровня представления и просто установить угол toValue. Не нужно сохранять old_value

-(void) MoveNeedleToAngle:(float) targetRadians{ 

    CABasicAnimation *animation =[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    animation.duration=5.0;
    animation.fillMode=kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    animation.removedOnCompletion=NO;

    animation.fromValue = [NSNumber numberWithFloat: [[layer.presentationLayer valueForKeyPath: @"transform.rotation"] floatValue]];
    animation.toValue = [NSNumber numberWithFloat:targetRadians];
   // layer.transform= CATransform3DMakeRotation(rads, 0, 0, 1);
   [layer addAnimation:animation forKey:@"rotate"];
}

Другой способ, которым я нашел (прокомментированная строка выше), вместо использования fromValue и toValue просто устанавливает преобразование слоя. Это создаст ту же анимацию, но презентационный слой и модель будут синхронизированы.