Анимация UIView переходит в начало


Я запускаю этот код...

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{

                     CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.settingsView.frame.size.width, 0);
                     CGAffineTransform speedTransform = CGAffineTransformMakeTranslation(-self.speedView.frame.size.width, 0);

                     self.settingsView.transform = settingsTransform;
                     self.speedView.transform = speedTransform;

                 } completion:nil];

Но когда он работает, представления перескакивают половину преобразования в противоположном направлении, прежде чем сдвинуться на половину позиции в правильном направлении.

Я замедлил продолжительность анимации до 5 секунд, но начальный скачок мгновенный и половина преобразования в неправильном направлении.

Когда я анимирую назад, используя этот код...

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];
Он делает в точности то же самое.

Результатом является то, что конечное движение является половина желаемого преобразования, как он прыгает половину преобразования в неправильном направлении сначала.

Я действительно не могу понять, почему это происходит?

Любые идеи.

:: EDIT::

Прояснение некоторой возможной двусмысленности.

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

Вы можете увидеть этот эффект, вставив вид в контроллер вида и кнопку для запуска анимации.

Спасибо

8 25

8 ответов:

У меня была точно такая же проблема, поэтому вот решение, которое я придумал.

    CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, translation.x, translation.y);
    [UIView animateWithDuration:0.25 animations:^{
        _assetImageView.transform = transform;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
    }];

Так я называю [себя.вид layoutIfNeeded]; внутри анимированного блока. Без этого он имеет ту же проблему, что и вы, и сначала прыгает на расстояние отрицательного перевода, а затем анимируется в правильное положение оттуда. Я вызываю это из контроллера вида, поэтому self является подклассом UIViewController. В вашем случае " самость.вид " может не существовать, но я надеюсь, что вы поняли идею.

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

Некоторые детали:

Представление, которое это делало, имело ряд масштабов и уже переводилось в стек.

Решение:

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

    UIView.animateKeyframesWithDuration(0.4, delay: 0.0, options: [.CalculationModeCubic], animations: { () -> Void in
        //reset start point
        UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.01, animations: { () -> Void in
            self.element.transform = initialTransform
        })

        UIView.addKeyframeWithRelativeStartTime(0.01, relativeDuration: 0.99, animations: { () -> Void in
            self.element.transform = finalTransform
        })
    }, completion: nil)

Хорошо, посмотрев видео WWDC еще раз, они утверждают, что одна из первых вещей, которые вы должны сделать при использовании AutoLayout, - это удалить все вызовы setFrame.

Из-за сложности экрана я полностью удалил авто-макет и теперь использую расположение кадра для перемещения вида по экрану.

Спасибо

Я спросил техническую поддержку Apple об этой проблеме и получил этот ответ, так что это ошибка.

IOS 8 в настоящее время демонстрирует известную ошибку в анимации UIKit, где анимация преобразования получает неправильное значение fromValue (в первую очередь влияющее на положение анимированных объектов, заставляющее их казаться " прыгающими" неожиданно на старте по анимации).

[...]

Обходной путь до тех пор, пока потенциальное исправление не будет доставлено, должен упасть до Основной API для анимации кодируйте свои анимации.

Вот улучшенная версия ответа Андреаса Ключевое отличие заключается в том, что вы можете указать только один ключевой кадр и получить меньше кода

UIView.animateKeyframes(withDuration: animationDuration, delay: 0.0, options: [], animations: {
  UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1.0, animations: {
    animatedView.transform = newTransform
    })
  }, completion: nil)

Делает ваших settingsView или спидвеистов уже есть преобразование, примененное до этого анимация происходит?

Если преобразования для этих представлений не являются преобразованием идентичности (он же CGAffineTransformIdentity, он же no transformation), вы не можете получить к ним доступ .свойства фрейма.

Свойства фрейма UIViews недопустимы, если к ним применено преобразование. Вместо этого используйте "границы".

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

[UIView animateWithDuration:0.2
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
                 animations:^{
                     self.settingsView.transform = CGAffineTransformIdentity;
                     self.speedView.transform = CGAffineTransformIdentity;
                 } completion:nil];

Вот пример кода, который я использовал для тестирования с помощью шаблона simple view controller:

Myviewcontroller.М:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.animatedView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 160, 80)];
    self.animatedView.backgroundColor = [UIColor yellowColor];

    [UIView animateWithDuration:0.2
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         CGAffineTransform settingsTransform = CGAffineTransformMakeTranslation(self.animatedView.frame.size.width, 0);

                         self.animatedView.transform = settingsTransform;

                     }
                     completion:nil];
    self.buttonToTest = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.buttonToTest.frame = CGRectMake(90, 20, 80, 40);
    [self.buttonToTest setTitle:@"Click Me!" forState:UIControlStateNormal];
    [self.buttonToTest addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];

    // set-up view hierarchy
    [self.view addSubview:self.buttonToTest];
    [self.view addSubview: self.animatedView];

}

- (void) buttonClicked
{
    [UIView animateWithDuration:.2
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         self.animatedView.transform = CGAffineTransformIdentity;

                     }
                     completion:nil];
}

У меня была эта проблема, и я решил ее следующим образом:

  1. привязка исходного вида
  2. Добавьте временное представление, которое копирует представление, которое вы хотите анимировать
  3. Выполняйте анимацию, которая теперь будет такой, как задумано
  4. Удалите временное представление и отобразите исходное представление с конечным состоянием

Надеюсь, это поможет.