RootViewControllersをアニメーションで交換するときに少し問題があります。これが私が使用しているコードです:
[UIView transitionWithView:self.window duration:0.8 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
self.window.rootViewController = self.navigationController;
} completion:nil];
アニメーションの直前に画面が真っ黒になり、アニメーションが発生することを除いて、それは一種の作品です。オリジナルのrootViewControllerがアニメーションの直前に削除されているようです。何か案は?
transitionWithView
は、指定されたコンテナービューのサブビューをアニメーション化することを目的としています。ルートビューコントローラの変更をアニメーション化することはそれほど簡単ではありません。私は副作用なしでそれをしようとする長い時間を費やしました。見る:
ナビゲーションコントローラースタック、サブビュー、モーダルコントローラーを使用せずにビューコントローラーの変化をアニメーション化しますか?
編集:参照された回答からの抜粋を追加
[UIView transitionFromView:self.window.rootViewController.view
toView:viewController.view
duration:0.65f
options:transition
completion:^(BOOL finished){
self.window.rootViewController = viewController;
}];
私はこれがかなり古い質問であることを認識していますが、受け入れられた回答も代替案も良い解決策を提供しませんでした(アニメーションが終了すると、新しいルートビューコントローラーのナビゲーションバーが白から背景色に点滅し、非常に不快です) 。
これを修正するには、最初のビューコントローラーの最後の画面のスナップショットを作成し、2番目(宛先)のビューコントローラーの上にオーバーレイし、必要に応じてアニメーション化しますafter 2番目のビューコントローラーをルートとして設定します。
UIView *overlayView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
[self.destinationViewController.view addSubview:overlayView];
self.window.rootViewController = self.destinationViewController;
[UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
overlayView.alpha = 0;
} completion:^(BOOL finished) {
[overlayView removeFromSuperview];
}];
編集: Swift 3バージョンのコード:
let overlayView = UIScreen.main.snapshotView(afterScreenUpdates: false)
destinationViewController.view.addSubview(overlayView)
window.rootViewController = destinationViewController
UIView.animate(withDuration: 0.4, delay: 0, options: .transitionCrossDissolve, animations: {
overlayView.alpha = 0
}, completion: { finished in
overlayView.removeFromSuperview()
})
私は transitionWithView:duration:options:animations:completion: を見つけて、より信頼できる結果を生成しました。
[UIView transitionWithView:window
duration:0.3
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[fromView removeFromSuperview];
[window addSubview:toView];
window.rootViewController = toViewController;
}
completion:NULL];
ルートビューコントローラーを設定するための完了ブロックまでそのままにしておくと、view(Will/Did)Appearなどのメソッドの実行中に
self.view.window.rootViewController
以前のビューコントローラに設定されたままになります。これらのメソッドの実行中に、私が行ったようにrootViewControllerへの参照を他のコードに渡す必要がない限り、これはほとんどの状況で問題になることはありません。
(この回答を書いている時点で)現在受け入れられている回答は、アニメーション中にナビゲーションバーなどのUI要素を正しく配置しないか、他のlayoutグリッチにつながる可能性があるため、理想的ではありません。 Marko Nikolovskiの回答 。ただし、アニメーションの目的で、現在のビューコントローラーのビューの snapshot を次のビューコントローラーのビューの上にプッシュすることは、どのような種類のビューコントローラーにも使用できないため、理想的ではありません。スナップショットは単なるstatic imageなので、次のView Controllerへの移行中にアニメーションが発生しています。
ccloggの基本的な考え方 を取るこれは、アルファ値を気にしない2つのビューコントローラ間のスムーズな遷移のための私の実装です。
/// Replaces the window's current `rootViewController` with the `newViewController`
/// passed as a parameter. If `animated`, the window animates the replacement
/// with a cross dissolve transition.
///
/// - Parameters:
/// - newViewController: The view controller that replaces the current view controller.
/// - animated: Specifies if the transition between the two view controllers is animated.
/// - duration: The transition's duration. (Ignored if `animated == false`)
private func swapCurrentViewController(with newViewController: UIViewController,
animated: Bool = true,
duration: TimeInterval = 1) {
// Get a reference to the window's current `rootViewController` (the "old" one)
let oldViewController = window?.rootViewController
// Replace the window's `rootViewController` with the new one
window?.rootViewController = newViewController
if animated, let oldView = oldViewController?.view {
// Add the old view controller's view on top of the new `rootViewController`
newViewController.view.addSubview(oldView)
// Remove the old view controller's view in an animated fashion
UIView.transition(with: window!,
duration: duration,
options: .transitionCrossDissolve,
animations: { oldView.removeFromSuperview() },
completion: nil)
}
}
ウィンドウのrootViewController
before を開始してトランジションまたはアニメーションを開始することが重要です。これは、新しいView Controllerがコンテキスト(正しいレイアウトマージンなど)を知るための方法です。
????これは、何らかの理由で本当にウィンドウのrootViewController
を置き換える必要がある場合に使用する方法です。ただし、私は、アーキテクチャの観点から、他の2つのビューコントローラ間の遷移の処理を担当するビューコントローラを作成し、それをウィンドウのrootViewController
そしてnever change it。 this answer でも同様の質問によく説明されています。
私にとってうまくいった解決策は、Marko Nikolovskiの答えを少し変更したものでした。既存のルートビューコントローラーにはアニメーション化されたスピナーがあり、アニメーションがフリーズしたため、スナップショットが奇妙に見えました。最終的に、私は(現在のルートビューコントローラー内で)以下を実行できました。
NextRootViewController *nextRootVC = [self.storyboard instantiateViewControllerWithIdentifier:@"NextRootViewController"];
self.view.window.rootViewController = nextRootVC;
[nextRootVC addSubview:self.view];
[UIView animateWithDuration:0.4 delay:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
self.view.alpha = 0;
} completion:^(BOOL finished) {
[self.view removeFromSuperview];
}];