34

問題

通話中にUINavigationController(ルート ビュー コントローラーが既にプッシュされているので) を提示すると、奇妙な動作が発生することに気付きました。UIViewControllerAnimatedTransitioning

  • ナビゲーション コントローラーが表示されたに通話中のステータス バーが有効になっている場合、ナビゲーション コントローラーは期待どおりにビューを下にシフトします。ただし、通話が終了しても、コントローラーはビューを上に戻さず、ステータス バーの下に 20p のギャップが残ります。
  • コントローラーを表示する前に通話中ステータス バーが有効になっている場合、コントローラーはステータス バーをまったく考慮せず、高さ 44p のナビゲーション バーの 4p が 40p ステータス バーの下からはみ出します。通話が終了すると、コントローラは通常の 20p ステータス バーに合わせてビューを下に移動します。

*注: これは、通話中のステータス バーを簡単に有効/無効にできるようにシミュレーターでテストされましたが、テスターは実際の電話でこの現象を観察しました。

私の(部分的な)回避策

ステータスバーが異常な高さだった場合、プレゼンテーション中にコントローラーのフレームを調整することで問題を回避しました。

@interface CustomAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
@end

@implementation CustomAnimationController

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *container = [transitionContext containerView];

    CGRect frame = [transitionContext finalFrameForViewController:toController];
    if (CGRectEqualToRect(frame, CGRectZero))
    {
        // In my experience, the final frame is always a zero rect, so this is always hit
        UIEdgeInsets insets = UIEdgeInsetsZero;
        // My "solution" was to inset the container frame by the difference between the 
        // actual status bar height and the normal status bar height
        insets.top = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - 20;
        frame = UIEdgeInsetsInsetRect(container.bounds, insets);
    }

    toController.view.frame = frame;
    [container addSubview:toController.view];

    // Perform whiz-bang animation here
}    

@end

この解決策により、ナビゲーション バーがステータス バーの下にあることが保証されますが、通話が終了したときにナビゲーション コントローラーが元に戻ることはありません。したがって、アプリは少なくとも使用可能ですが、通話が終了した後、ナビゲーション バーの上に醜い 20p のギャップがあります。

より良い方法はありますか?

ナビゲーション コントローラーが通話中のステータス バーを独自に考慮していることを確認するための重要な手順がいくつかありませんか? 組み込みのモーダル プレゼンテーション スタイルで表示すると、問題なく動作します。

私の意見では、これは UIKit のバグのように見えます — 結局、ナビゲーション コントローラーはUIApplicationWillChangeStatusBarFrameNotification(問題の 2 番目のポイントを参照) を受け取っているようです。他の誰かがこの問題に遭遇し、より良い方法を見つけた場合は、解決策をいただければ幸いです。

4

5 に答える 5

1

私は同じ問題を抱えていましたが、問題は私が提示していたビューにあり、通話中のバーのために自動的に 20pt 調整されました。ただし、ビューをコンテナーに挿入したため、コンテナーの境界に一致するようにフレームをリセットする必要がありました。

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    UIView* destinationView = [transitionContext viewForKey:UITransitionContextToViewKey];
    UIView* container = transitionContext.containerView;

    // Make sure destination view matches container bounds
    // This is necessary to fix the issue with in-call bar
    // which adjusts the view's frame by 20pt.
    destinationView.frame = container.bounds;

    // Add destination view to container
    [container insertSubview:destinationView atIndex:0];

    // [reducted]
}
于 2016-03-27T10:07:17.537 に答える
0

ステータスバーの高さが変化したときに呼び出されるように、layoutSubviews にフレームを設定するだけです。一般に、経験則として、layoutSubviews でのみすべてのフレーム設定を行います。

于 2015-02-16T14:19:13.217 に答える
0

これは、アプリのデリゲートに入れ、問題を解決した回避策です。

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
    if (newStatusBarFrame.size.height < 40) {
        for (UIView *view in self.window.subviews) {
            view.frame = self.window.bounds;
        }
    }
}
于 2016-01-10T22:28:07.703 に答える