U I P e r c e n t DrivenInteractiveTransition終了時に無関係なアニメーションを生成する
-
21-12-2019 - |
質問
私は対話型のカスタムプッシュトランジションを使用しています UIPercentDrivenInteractiveTransition
.ジェスチャ認識器は、インタラクションコントローラの呼び出しに成功します updateInteractiveTransition
.同様に、インタラクションコントローラーを呼び出すと、アニメーションが正常に完了します finishInteractiveTransition
.
しかし、時には私は最後に気が散るアニメーションの余分なビットを得る(それはアニメーションの後半を繰り返すように見える)。合理的に単純なアニメーションでは、iPhone5でこの症状を見ることはめったにありません(遅いラップトップで作業するときはシミュレーターで日常的に見アニメーションをより計算上高価にすると(例:たくさんの影、さまざまな方向をアニメーション化する複数のビューなど。)、デバイス上のこの問題の頻度が増加します。
他の誰かがこの問題を見て、アニメーションを合理化する以外の解決策を見つけましたか(私は確かにとにかくやるべきです)、および/または私自身のinteraction controllersを書く以外の解決策を考え出しましたか?ザ- UIPercentDrivenInteractiveTransition
アプローチはそれに一定の優雅さを持っていますが、私はそれが非決定論的に誤動作するという事実に不安です。他の人がこの行動を見たことがありますか?誰かが他の解決策を知っていますか?
効果を説明するには、下の画像を参照してください。アニメーションが終了すると、2番目のシーンである赤いビューが、アニメーションの後半部分を2回繰り返すように見えることに注意してください。
このアニメーションは、次のように生成されます。:
何度も電話をかけて
updateInteractiveTransition
, 、0%から40%への更新を進めます%;一時的に一時停止する(インタラクティブなトランジションと、次の結果の完了アニメーションを区別できます
finishInteractiveTransition
);その後、呼び出します
finishInteractiveTransition
アニメーションを完成させるには;とアニメーションコントローラのアニメーションの
completion
呼び出しをブロックするcompleteTransition
のためにtransitionContext
, 、すべてをきれいにするために。
いくつかの診断を行うと、その無関係なアニメーションをトリガーするのはこの最後のステップであるように見えます。アニメーションコントローラーの完了ブロックは、アニメーションが終了したときに呼び出されますが、呼び出すとすぐに呼び出されます completeTransition
, 、アニメーションの最後のビットを繰り返すことがあります(特に複雑なアニメーションを使用する場合)。
私はそれが関連しているとは思わないが、これは対話的な遷移を実行するようにナビゲーションコントローラを設定するための私のコードである:
- (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;
}
私の PushAnimator
は:
@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
注、私が呼び出す場所にロギングステートメントを置くと completeTransition
, 、私が呼び出した後、この無関係なアニメーションが発生することがわかります completeTransition
(アニメーションは実際にその時点で行われていたにもかかわらず)。これは、その余分なアニメーションが呼び出しの結果であった可能性があることを示唆しています completeTransition
.
参考までに、私はジェスチャー認識器でこの実験を行いました:
- (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];
}
}
}
私はまた、呼び出してそれをしました updateInteractiveTransition
と finishInteractiveTransition
手動で(式からジェスチャ認識器を排除する)、それはまだこの奇妙な動作を示します:
[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];
});
});
結論として、私はこれが分離された問題であると結論付けました UIPercentDrivenInteractiveTransition
複雑なアニメーションで。私はそれらを単純化することによって問題を最小限に抑えることができます(例えばスナップショットビューとアニメーションスナップショットビュー)。私はまた、私が使用しないことでこれを解決できると思う UIPercentDrivenInteractiveTransition
そして、補間しようとせずに、アニメーション自体を行うだろう私自身の相互作用コントローラを、書きます animationWithDuration
ブロック。
しかし、誰かが他のトリックを使用することを理解したかどうか疑問に思っていました UIPercentDrivenInteractiveTransition
複雑なアニメーションで。
解決
私は似たようなものを見てきました。私は2つの可能な回避策を持っています。1つは、アニメーション完了ハンドラで遅延パフォーマンスを使用することです:
} 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;
}];
他の可能性は次のとおりです:パーセントドライブアニメーションを使用しないでください!私はしました 決して インタラクティブなカスタムアニメーションを駆動するときに、このような問題がありました 私自身 手動で。
他のヒント
この問題はシミュレータでのみ発生します。
ソリューション:自己。interactiveAnimator.completionSpeed=0.999;
ここで報告されたバグ: http://openradar.appspot.com/14675246
私の場合、このエラーの理由は、複数回アニメーション化されているビューのフレームを設定していました。私は一度だけビューフレームを設定していて、私の問題を修正しました。
したがって、この場合、「toViewController」のフレーム。view"が二度設定されたため、アニメーションが不要な動作をするようになりました