これは問題であり、部分的な解決策でもあります。
*サンプルプロジェクトはこちら:
https://github.com/JosephLin/TransitionTest
問題 1:
を使用している場合、遷移アニメーションの開始時transitionFromViewController:...
に で作成されたレイアウトが表示されません。つまり、アニメーション中にプレレイアウト ビューが表示され、そのコンテンツはアニメーション後にレイアウト後の位置にスナップされます。toViewController
viewWillAppear:
問題 2:
ナビゲーション バーの背景をカスタマイズするUIBarButtonItem
と、問題 1 と同様に、アニメーションの前にバー ボタンが間違ったサイズ/位置で表示され、アニメーションが終了すると正しいサイズ/位置にスナップします。
この問題を実証するために、いくつかのカスタム ビュー遷移を実行するベアボーン カスタム コンテナー コントローラーを作成しました。ビュー間でアニメーションをプッシュするのではなく、クロスディゾルブを行うのは、ほとんど UINavigationController のコピーです。
「プッシュ」メソッドは次のようになります。
- (void)pushController:(UIViewController *)toViewController
{
UIViewController *fromViewController = [self.childViewControllers lastObject];
[self addChildViewController:toViewController];
toViewController.view.frame = self.view.bounds;
NSLog(@"Before transitionFromViewController:");
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{}
completion:^(BOOL finished) {
[toViewController didMoveToParentViewController:self];
}];
}
ここで、DetailViewController
(プッシュしているビュー コントローラー) でコンテンツをレイアウトする必要がありますviewWillAppear:
。viewDidLoad
その時点で正しいフレームがないため、それを行うことはできません。
デモンストレーションのために、ラベルを、、およびDetailViewController
で異なる場所と色に設定します。viewDidLoad
viewWillAppear
viewDidAppear
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%s", __PRETTY_FUNCTION__);
CGRect rect = self.descriptionLabel.frame;
rect.origin.y = 50;
self.descriptionLabel.frame = rect;
self.descriptionLabel.text = @"viewDidLoad";
self.descriptionLabel.backgroundColor = [UIColor redColor];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"%s", __PRETTY_FUNCTION__);
CGRect rect = self.descriptionLabel.frame;
rect.origin.y = 200;
self.descriptionLabel.frame = rect;
self.descriptionLabel.text = @"viewWillAppear";
self.descriptionLabel.backgroundColor = [UIColor yellowColor];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"%s", __PRETTY_FUNCTION__);
CGRect rect = self.descriptionLabel.frame;
rect.origin.y = 350;
self.descriptionLabel.frame = rect;
self.descriptionLabel.text = @"viewDidAppear";
self.descriptionLabel.backgroundColor = [UIColor greenColor];
}
を押すと、アニメーションの開始時DetailViewController
にラベルが表示さy =200
れ (左の画像)、y = 350
アニメーションが終了した後にジャンプします (右の画像)。
アニメーション前後の期待されるビュー。
y=50
しかし、アニメーションが行われる前にで作成されたレイアウトが作成されviewWillAppear
なかったかのように、ラベルは にありました (左の画像)。ただし、ラベルの背景が黄色 ( で指定された色viewWillAppear
) に設定されていることに注意してください。
アニメ冒頭のレイアウトがおかしい。バー ボタンも間違った位置/サイズで始まることに注意してください。
コンソール ログ
TransitionTest[49795:c07] -[DetailViewController viewDidLoad]
TransitionTest[49795:c07] transitionFromViewController の前:
TransitionTest[49795:c07] -[DetailViewController viewWillAppear:]
TransitionTest[49795:c07] -[DetailViewController viewWillLayoutSubviews]
TransitionTest[49795:c07 ] -[DetailViewController viewDidLayoutSubviews]
TransitionTest[49795:c07] -[DetailViewController viewDidAppear:] AFTERが呼び出され
たことに注意viewWillAppear:
transitionFromViewController:
問題 1 の解決策
よし、ここから部分解の部分に入る。beginAppearanceTransition:
とendAppearanceTransition
を明示的に呼び出すことによりtoViewController
、遷移アニメーションが発生する前に、ビューは正しいレイアウトになります。
- (void)pushController:(UIViewController *)toViewController
{
UIViewController *fromViewController = [self.childViewControllers lastObject];
[self addChildViewController:toViewController];
toViewController.view.frame = self.view.bounds;
[toViewController beginAppearanceTransition:YES animated:NO];
NSLog(@"Before transitionFromViewController:");
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{}
completion:^(BOOL finished) {
[toViewController didMoveToParentViewController:self];
[toViewController endAppearanceTransition];
}];
}
viewWillAppear:
BEFORE TransitionTest[ 18398transitionFromViewController:
:c07] -[DetailViewController viewDidLoad]
TransitionTest[18398:c07] -[DetailViewController viewWillAppear:]
TransitionTest[18398:c07] TransitionFromViewController の前:
TransitionTest[18398:c07] -[DetailViewController viewWillLayoutSubviews]
TransitionTest [18398:c07] -[DetailViewController viewDidLayoutSubviews]
TransitionTest[18398:c07] -[DetailViewController viewDidAppear:]
しかし、それでは問題 2 は解決しません。
なんらかの理由で、ナビゲーション バーのボタンは、遷移アニメーションの開始時に間違った位置/サイズで開始されます。私は正しい解決策を見つけるために多くの時間を費やしましたが、運がありませんでした. 私はそれがバグだと感じ始めていtransitionFromViewController:
ますUIAppearance
。この質問に対してあなたが提供できる洞察をいただければ幸いです。ありがとう!
私が試した他の解決策
[self.view addSubview:toViewController.view];
前に電話するtransitionFromViewController:
実際には、ユーザーに正確な結果を提供し、問題 1 と 2 の両方を修正します。問題は、viewWillAppear
両方viewDidAppear
が 2 回呼び出されることです! で大規模なアニメーションや計算を行いたい場合は問題がありviewDidAppear
ます。
[toViewController viewWillAppear:YES];
前に電話するtransitionFromViewController:
を呼び出すのとほとんど同じだと思いますbeginAppearanceTransition:
。問題 1 は修正されますが、問題 2 は修正されません。さらに、ドキュメントには、viewWillAppear
直接呼び出してはいけないと書かれています。
[UIView animateWithDuration:]
の代わりに使用transitionFromViewController:
このように: [self addChildViewController:toViewController]; [self.view addSubview:toViewController.view]; toViewController.view.alpha = 0.0;
[UIView animateWithDuration:0.5 animations:^{
toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
[toViewController didMoveToParentViewController:self];
}];
問題 2 は修正されますが、ビューはレイアウトviewDidAppear
(ラベルは緑、y=350) で開始されます。また、クロスディゾルブは使用するほど良くありませんUIViewAnimationOptionTransitionCrossDissolve