У меня возникла проблема при установке приложения iPhone на фоновое изображение, нажав кнопку выхода, а затем перезапустив его, нажав значок запуска на главном экране: представление приложения вернется в исходное состояние, как я этого хочу, но прежде что он кратковременно мигает на более раннем, неправильном состоянии отображения на экране.
Фон
Мое главное представление состоит в основном из последовательности взаимосвязанных вызовов UIAnimateWithDuration. Поведение, которое я хочу всякий раз, когда происходит какое-либо прерывание, заключается в reset анимации в ее исходное состояние (если только анимация не закончилась и приложение не вступила в статическую заключительную фазу), и начинайте с нее всякий раз, когда приложение возвращается к активному и видимое состояние.
После изучения предмета я узнал, что мне нужно два типа кода обработки прерываний, чтобы обеспечить хороший ux: "мгновенный" и "плавный". У меня есть метод resetAnimation, который мгновенно восстанавливает свойства представления в исходное состояние, а метод pauseAnimation, который быстро анимируется в одно и то же состояние, с дополнительной меткой с надписью "paused", которая исчезает в верхней части представления.
Двойное нажатие кнопки выхода
Причиной этого является вариант использования "двойного нажатия кнопки выхода", который на самом деле не скрывает ваше представление или не помещает вас в фоновое состояние, он просто прокручивает бит, чтобы показать меню многозадачности внизу. Таким образом, сброс состояния просмотра мгновенно в этом случае выглядел очень уродливо. Анимированный переход и сообщение пользователю, которого вы приостановили, выглядели как лучшая идея.
Этот случай работает хорошо и сглаженно, реализуя метод делегирования applicationWillResignActive в приложении App Delegate и вызывая pauseAnimation оттуда. Я обращаюсь с возвратом из этого меню многозадачности, реализуя метод делегирования applicationDidBecomeActive и вызывая оттуда мой метод resumeAnimation, который исчезает из "приостановленной" метки, если он есть, и запускает мою анимационную последовательность из начального состояния.
Все работает отлично, нигде не мерцает.
Посещение флипсайд
Мое приложение построено по шаблону "утилита" Xcode, поэтому у него есть обратный взгляд, чтобы показать информацию/настройки. Я обращаюсь к разворачиванию и возвращаюсь к основному виду, реализуя эти два метода делегата в моем основном контроллере представления:
-
(пустоты) viewDidDisappear: (BOOL) анимированные
-
(пустоты) viewDidAppear: (BOOL) анимированные
Я вызываю свой resetAnimation в методе viewDidDisappear и resumeAnimation в viewDidAppear. Все это прекрасно работает, основным видом является его начальное состояние с самого начала перехода к видимому состоянию - никаких неожиданных вспышек неправильных состояний анимации чего-либо. Но:
Нажатие кнопки выхода и перезапуск с моего значка приложения (багги!)
Здесь начинается проблема. Когда я нажимаю кнопку выхода один раз, и мое приложение начинает переход к фону, происходят две вещи. Во-первых, здесь также вызывается applicationWillResignActive, поэтому также запускается мой метод pauseAnimation. Это не нужно, так как переход не обязательно должен быть гладким здесь - представление просто статично и "масштабируется", чтобы показать главный экран, - но что вы можете сделать? Ну, это не повредило бы, если бы я просто мог вызвать resetAnimation до того момента, когда система сделает снимок представления.
В любом случае, во-вторых, вызывает вызов applicationDidEnterBackground в App Delegate. Я попытался вызвать resetAnimation оттуда, чтобы представление было в правильном состоянии, когда приложение вернется, но это, похоже, не работает. Кажется, что "моментальный снимок" уже был взят, и поэтому, когда я нажимаю значок запуска приложения и relauch, неправильное состояние отображения мгновенно мигает на экране, прежде чем появится правильное начальное состояние. После этого он отлично работает, анимации идут так, как будто они должны, но это уродливое мерцание в этот возобновленный момент не исчезнет, независимо от того, что я пробую.
В принципе, что мне нужно, какой точный момент делает система для моментального снимка? И, следовательно, каков был бы правильный метод делегата или обработчик уведомлений, чтобы подготовить мой взгляд на получение "сувенирной фотографии"?
PS. Тогда есть default.png, который, кажется, не отображается только при первом запуске, но также всякий раз, когда процессор, имеющий трудное время или возвращающийся к приложению, ненадолго задерживается по какой-то другой причине. Это немного уродливо, особенно если вы возвращаетесь к своему взгляду на обратном пути, который выглядит совершенно иначе, чем ваш вид по умолчанию. Но это такая основная функция iOS, я предполагаю, что я даже не должен пытаться ее выяснить или контролировать:)
Изменить: поскольку люди запрашивали фактический код, и мое приложение уже было выпущено после того, как задали этот вопрос, я отправлю его здесь. (Приложение называется Sweetest Kid, и если вы хотите посмотреть, как он работает, он здесь: http://itunes.apple.com/app/sweetest-kid/id476637106?mt=8)
Здесь мой метод pauseAnimation - resetAnimation почти идентичен, за исключением того, что его анимационный вызов имеет нулевую продолжительность и задержку, и он не показывает метку "Приостановил". Одна из причин, по которой я использую UIAnimation для reset, вместо того, чтобы просто назначать новые значения, заключается в том, что по какой-то причине анимация просто не прекращалась, если я не использовал UIAnimation. Во всяком случае, здесь метод pauseAnimation:
- (void)pauseAnimation {
if (currentAnimationPhase < 6 || currentAnimationPhase == 255) {
// 6 means finished, 255 is a short initial animation only showing at first launch
self.paused = YES;
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionAllowUserInteraction |
UIViewAnimationOptionBeginFromCurrentState |
UIViewAnimationOptionCurveEaseInOut |
UIViewAnimationOptionOverrideInheritedCurve |
UIViewAnimationOptionOverrideInheritedDuration
animations:^{
pausedView.alpha = 1.0;
cameraImageView.alpha = 0;
mirrorGlowView.alpha = 0;
infoButton.alpha = 1.0;
chantView.alpha = 0;
verseOneLabel.alpha = 1.0;
verseTwoLabel.alpha = 0;
verseThreeLabel.alpha = 0;
shine1View.alpha = stars1View.alpha = stars2View.alpha = 0;
shine1View.transform = CGAffineTransformIdentity;
stars1View.transform = CGAffineTransformIdentity;
stars2View.transform = CGAffineTransformIdentity;
finishedMenuView.alpha = 0;
preparingMagicView.alpha = 0;}
completion:^(BOOL finished){
pausedView.alpha = 1.0;
cameraImageView.alpha = 0;
mirrorGlowView.alpha = 0;
infoButton.alpha = 1.0;
chantView.alpha = 0;
verseOneLabel.alpha = 1.0;
verseTwoLabel.alpha = 0;
verseThreeLabel.alpha = 0;
shine1View.alpha = stars1View.alpha = stars2View.alpha = 0;
shine1View.transform = CGAffineTransformIdentity;
stars1View.transform = CGAffineTransformIdentity;
stars2View.transform = CGAffineTransformIdentity;
finishedMenuView.alpha = 0;
preparingMagicView.alpha = 0;
}];
askTheMirrorButton.enabled = YES;
againButton.enabled = NO;
shareOnFacebookButton.enabled = NO;
emailButton.enabled = NO;
saveButton.enabled = NO;
currentAnimationPhase = 0;
[[cameraImageView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; // To remove the video preview layer
}
}