web-dev-qa-db-ja.com

UIViewControllerの通話中ステータスバーの問題

問題:

通話中のステータスバーが消えた後、モーダル表示されたView Controllerは上に戻りません。上部に20pxの空/透明なスペースが残ります。


通常:問題なし

enter image description here


通話中:問題なし

enter image description here


インコールが消えた後:

上部に高さ20ピクセルの空/透明なスペースを残し、下にオレンジ色のビューを表示します。ただし、透明領域の上にはステータスバーがまだ存在しています。ナビゲーションバーには、ステータスバー用のスペースも確保されています。

enter image description here

enter image description here


  • iOS 10ベース
  • モーダル表示のView Controller
  • カスタムモーダルプレゼンテーション
  • 背後のメインビューコントローラーはオレンジ色です
  • 自動レイアウトを使用しない
  • Landscapeに回転すると、20pxのIn-Call Barは20pxのギャップを残します。
  • 横向きのステータスバーの表示をオプトアウトします。 (つまり、ほとんどのストックアプリ)

アプリデリゲートを試してみました:

willChangeStatusBarFrame
didChangeStatusBarFrame

コントローラベースの通知も表示します:

UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame

上記の4つの方法すべてについて、提示されたビューのフレームを記録すると、フレームは常に(y:0)Originになります。


更新

View Controllerカスタムモーダルプレゼンテーション

    let storyboard = UIStoryboard(name: "StoryBoard1", bundle: nil)
    self.modalVC = storyboard.instantiateViewController(withIdentifier: "My Modal View Controller") as? MyModalViewController
    self.modalVC!.transitioningDelegate = self
    self.modalVC.modalPresentationStyle = .custom
    self.modalVC.modalPresentationCapturesStatusBarAppearance = true;
    self.present(self.modalVC!, animated: true, completion: nil)


    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        toViewController!.view.transform = CGAffineTransform(scaleX: 0.001, y: 0.001)

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.0, options: [.curveEaseOut], animations: { () -> Void in

            toViewController!.view.transform = CGAffineTransform.identity

        }, completion: { (completed) -> Void in

           transitionContext.completeTransition(completed)

        })
 }
17
Gizmodo

私もこの問題に直面しましたが、この方法を適用した後、問題はなくなりました。

iOSには、ステータスバーを処理するデフォルトのメソッドwillChangeStatusBarFrameがあります。このメソッドを入れて確認してください。

func application(_ application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect) {
    UIView.animate(withDuration: 0.35, animations: {() -> Void in
        let windowFrame: CGRect? = ((window?.rootViewController? as? UITabBarController)?.viewControllers[0] as? UINavigationController)?.view?.frame
        if newStatusBarFrame.size.height > 20 {
            windowFrame?.origin?.y = newStatusBarFrame.size.height - 20
            // old status bar frame is 20
        }
        else {
            windowFrame?.origin?.y = 0.0
        }
        ((window?.rootViewController? as? UITabBarController)?.viewControllers[0] as? UINavigationController)?.view?.frame = windowFrame
    })
}

このことがあなたのお役に立てば幸いです。
ありがとうございました

5
Jitendra Modi

私は3日間ソリューションを探していました。私はこの解決策が好きではありませんが、それを修正するより良い方法を見つけませんでした。

RootViewControllerビューの高さがウィンドウよりも20ポイント大きい場合、ステータスバーの高さの更新に関する通知がある場合、手動で正しい値を設定します。

AppDelegate.Swiftにメソッドを追加します

func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
        if let window = application.keyWindow {
            window.rootViewController?.view.frame = window.frame
        }
    }

その後、期待どおりに動作します(向きが変わった後でも)。私はこれにあまりにも多くの時間を費やしたので、それが誰かを助けることを願っています。

追伸少し点滅しますが、動作します。

5
Bws Sluk

これはUIKitのバグだと思います。カスタムトランジションを使用して表示された表示されたコントローラーのビューを含むcontainerViewは、ステータスバーが通常のサイズに戻ったときに完全に戻るようには見えません。 (通話中ステータスバーを閉じた後、ビュー階層を確認できます)

それを解決するために、プレゼンテーション時にカスタムプレゼンテーションコントローラーを提供できます。そして、表示コントローラーのビューをビュー階層に残す必要がない場合、プレゼンテーションコントローラーのtrueプロパティにshouldRemovePresentersViewを返すだけで済みます。

func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    return PresentationController(presentedViewController: presented, presenting: presenting)
}

class PresentationController: UIPresentationController {
    override var shouldRemovePresentersView: Bool {
        return true
    }
}

または、表示するコントローラーのビューを残す必要がある場合は、ステータスバーフレームの変化を観察し、containerViewをスーパービューと同じサイズに手動で調整できます

class PresentationController: UIPresentationController {
    override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.onStatusBarChanged),
                                               name: .UIApplicationWillChangeStatusBarFrame,
                                               object: nil)
    }

    @objc func onStatusBarChanged(note: NSNotification) {
        //I can't find a way to ask the system for the values of these constants, maybe you can
        if UIApplication.shared.statusBarFrame.height <= 20,
            let superView = containerView?.superview {
            UIView.animate(withDuration: 0.4, animations: {
                self.containerView?.frame = superView.bounds
            })
        }
    }
}
3
riadhluke

私は、パーソナルホスポットがステータスバーを変更するのと同じ問題を抱えていました。解決策は、ステータスバーフレームの変更に関するシステム通知に登録することです。これにより、レイアウトを更新でき、発生する可能性のあるレイアウトの問題を修正する必要があります。あなたのためにまったく同じように動作するはずの私のソリューションはこれです:

  • View Controllerで、viewWillAppearUIApplicationDidChangeStatusBarFrameNotificationを購読します

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(myControllerName.handleFrameResize(_:)), name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • セレクターメソッドを作成する

    func handleFrameResize(notification: NSNotification) {
    self.view.layoutIfNeeded() }
    
  • viewWillDisappearの通知センターからコントローラーを削除します

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • また、ステータスバーを担当するモーダルが必要なので、設定する必要があります

    destVC.modalPresentationCapturesStatusBarAppearance = trueビューを表示する前。

ステータスバーを変更する可能性のあるすべてのコントローラーにこれを実装するか、メソッドにselfを渡す、参照を保持してレイアウトを変更する、メソッドを持つなど、すべてのコントローラーに対してそれを行う別のクラスを作成することができます自己を削除します。コードを再利用するために知っています。

3
thibaut noah

この問題の解決策を探していました。実際、私はこれに似た新しい質問を投稿しました。ここ: iOSブルーロケーションナビゲーションバーがステータスバーをめちゃくちゃにするのを避ける方法

私を信じて、私はこれを数日間解決しており、iOSのステータスバーが通話中、ホットスポット、および場所によって変化するため、画面がめちゃくちゃになるのは本当に迷惑です。

Modiの答えを実装しようとしました。そのコードをAppDelegateに入れて少し変更しましたが、運はありません。 iOSは自動的にそれを行うので、自分で実装する必要はありません。

問題の原因を発見する前に、この特定の質問のすべての解決策を試しました。 AppDelegateのメソッドを実装する必要はありませんwillChangeStatusBar...またはstatusBarの変更を監視する通知を追加します。

また、画面をプログラムで実行することで、プロジェクトのフローの一部をやり直しました(ストーリーボードを使用しています)。そして、私は少し実験してから、以前のプロジェクトや他の現在のプロジェクトを調べて、なぜ彼らが適切に調整を行っているのか:)

一番下の行は:メイン画面にUITabBarControllerを間違った方法で表示しています。

modalPresentationStyleに常に注意してください。ノアのコメントのために、コードをチェックアウトするというアイデアを得ました。

サンプル:

func presentDashboard() {
    if let tabBarController = R.storyboard.root.baseTabBarController() {
        tabBarController.selectedIndex = 1
        tabBarController.modalPresentationStyle = .fullScreen
        tabBarController.modalTransitionStyle = .crossDissolve

        self.baseTabBarController = tabBarController
        self.navigationController?.present(tabBarController, animated: true, completion: nil)
    }
}
3
Glenn

1行のコードを使用してこの問題を解決します

Objective Cの場合

tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);

In Swift

self.tabBarController?.tabBar.autoresizingMask = 
  UIViewAutoresizing(rawValue: UIViewAutoresizing.RawValue(UInt8(UIViewAutoresizing.flexibleWidth.rawValue) | UInt8(UIViewAutoresizing.flexibleTopMargin.rawValue)))`

TabBarのautoresizingMaskを上から柔軟にするだけです。

1
Sahil_Saini

私の場合、ViewControllerにカスタムプレゼンテーションスタイルを使用しています。問題は、Y位置が適切に計算されないことです。元の画面の高さが736pであるとします。 view.frame.Origin.yview.frame.heightを印刷してみると、高さが716p、yが20であることがわかります。ただし、ディスプレイの高さは736-20(呼び出し中のステータスバーの余分な高さ)-20( y位置)。これが、ViewControllerの下部からビューが切り取られ、上部に20pのマージンがある理由です。ただし、戻ってNavigation Controllerのフレーム値を確認する場合。通話中のステータスバーが表示されているかどうかに関係なく、y位置は常に0です。

したがって、y位置をゼロに設定するだけです。

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let f = self.view.frame

    if f.Origin.y != 0 {
        self.view.frame = CGRect(x: f.Origin.x, y: 0, width: f.width, height: f.height)
        self.view.layoutIfNeeded()
        self.view.updateConstraintsIfNeeded()
    }
}
1
Kimi Chiu

コンテナビューに追加した後、表示するView Controllerのビューのフレームをコンテナビューの境界に設定してください。これで問題が解決しました。

containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds
0
Colin R