UipercordendreninteractiveTransition che produce un'animazione estranea quando fatta
-
21-12-2019 - |
Domanda
Sto usando una transizione push personalizzata interattiva con un UIPercentDrivenInteractiveTransition
. Il riconoscimento dei gesto chiama con successo il updateInteractiveTransition
del controller di interazione. Allo stesso modo, l'animazione completa con successo quando chiamo il finishInteractiveTransition
del controller di interazione.
Ma, a volte ottengo un po 'in più di animazione distraente alla fine (dove sembra ripetere l'ultima parte dell'animazione). Con animazioni ragionevolmente semplici, raramente vedo questo sintomo su iPhone 5 (anche se lo vedo regolarmente sul simulatore quando si lavora su laptop lento). Se rendo l'animazione più computazionalmente costosa (ad esempio un sacco di ombre, più viste che animano diverse direzioni, ecc.), La frequenza di questo problema sul dispositivo aumenta.
ha chiunque altro ha visto questo problema e ha capito una soluzione diversa dallo snellire le animazioni (che ho certamente dovuto fare comunque) e / o scrivere i miei controller di interazione? L'approccio UIPercentDrivenInteractiveTransition
ha una certa eleganza ad esso, ma sono a disagio con il fatto che si comporta male non deterministicamente. Altri hanno visto questo comportamento? Qualcuno sa di altre soluzioni?
Per illustrare l'effetto, vedere l'immagine qui sotto. Nota come la seconda scena, la vista rossa, quando l'animazione finisce, sembra ripetere l'ultima parte della sua animazione una seconda volta.
Questa animazione è generata da:
- .
-
chiamando ripetutamente
updateInteractiveTransition
, avanzando aggiornamento dallo 0% al 40%; -
Pausa momentaneamente (in modo da poter differenziare tra la transizione interattiva e l'animazione di completamento risultante da
finishInteractiveTransition
); -
quindi chiamare
finishInteractiveTransition
per completare l'animazione; e -
Il blocco generacodiccode di animazione del controller dell'animazione chiama
completion
per ilcompleteTransition
, al fine di pulire tutto su.
Facendo qualche diagnostica, sembra che sia questo ultimo passo che attiva quel bit estraneo di animazione. Il blocco di completamento del controller dell'animazione viene chiamato quando l'animazione è finita, ma non appena ho chiamato transitionContext
, a volte ripete l'ultimo bit dell'animazione (in particolare quando si utilizza animazioni complesse).
.
Non penso che sia rilevante, ma questo è il mio codice per configurare il controller di navigazione per eseguire transizioni interattive:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.delegate = self;
self.interationController = [[UIPercentDrivenInteractiveTransition alloc] init];
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
if (operation == UINavigationControllerOperationPush)
return [[PushAnimator alloc] init];
return nil;
}
- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController
{
return self.interationController;
}
.
Il mio completeTransition
è:
@implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 5.0;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.frame = CGRectOffset(fromViewController.view.frame, fromViewController.view.frame.size.width, 0);;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.frame = fromViewController.view.frame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
.
Nota, quando inserisco la dichiarazione di registrazione in cui chiamo PushAnimator
, posso vedere che questo bit estraneo di animazione avviene dopo aver chiamato completeTransition
(anche se l'animazione è stata davvero fatta in quel punto). Ciò suggerirebbe che l'animazione extra potrebbe essere stata il risultato della chiamata a completeTransition
.
FYI, ho fatto questo esperimento con un riconoscimento dei gesti:
- (void)handlePan:(UIScreenEdgePanGestureRecognizer *)gesture
{
CGFloat width = gesture.view.frame.size.width;
if (gesture.state == UIGestureRecognizerStateBegan) {
[self performSegueWithIdentifier:@"pushToSecond" sender:self];
} else if (gesture.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [gesture translationInView:gesture.view];
[self.interactionController updateInteractiveTransition:ABS(translation.x / width)];
} else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled)
{
CGPoint translation = [gesture translationInView:gesture.view];
CGPoint velocity = [gesture velocityInView:gesture.view];
CGFloat percent = ABS(translation.x + velocity.x * 0.25 / width);
if (percent < 0.5 || gesture.state == UIGestureRecognizerStateCancelled) {
[self.interactionController cancelInteractiveTransition];
} else {
[self.interactionController finishInteractiveTransition];
}
}
}
.
L'ho fatto anche chiamando manualmente il completeTransition
e updateInteractiveTransition
(eliminando il riconoscimento dei gesti dall'equazione), e mostra ancora questo strano comportamento:
[self performSegueWithIdentifier:@"pushToSecond" sender:self];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.interactionController updateInteractiveTransition:0.40];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.interactionController finishInteractiveTransition];
});
});
.
Bottom line, ho concluso che questo è un problema isolato a finishInteractiveTransition
con animazioni complesse. Posso ridurre al minimo il problema semplificandoli (ad es. G. SnapShotting e Views snapshotted animate). Sospetto anche che potrei risolvere questo non usando UIPercentDrivenInteractiveTransition
e scrivendo il mio controller di interazione, che farebbe l'animazione stessa, senza cercare di interpolare il blocco UIPercentDrivenInteractiveTransition
.
Ma mi stavo chiedendo se qualcuno ha capito a nessun altro trucco per usare animationWithDuration
con animazioni complesse.
Soluzione
Ho visto qualcosa di simile.Ho due possibili soluzioni alternative.Uso per utilizzare prestazioni ritardate nel gestore di completamento dell'animazione:
} completion:^(BOOL finished) {
double delayInSeconds = 0.1;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
BOOL cancelled = [transitionContext transitionWasCancelled];
[transitionContext completeTransition:!cancelled];
});
self.interacting = NO;
}];
.
L'altra possibilità è: non usare l'animazione per percentuale-drive!Ho mai ha avuto un problema in questo modo quando si guida l'animazione personalizzata interattiva me stesso manualmente.
Altri suggerimenti
Questo problema sorge solo in simulatore.
Soluzione: self.interactiveanimator.ClionsPeed= 0.999;
Bug riportato qui: http://openradar.appspot.com/14675246
Il motivo per questo errore nel mio caso stava impostando il fotogramma della vista che viene animato più volte.Sto solo impostando la cornice di vista una volta e ha risolto i miei problemi.
Quindi in questo caso, il fotogramma di "Punto di vistaController.View" è stato impostato due volte, rendendo così l'animazione un comportamento indesiderato