問題:
通話中のステータスバーが消えた後、モーダル表示されたView Controllerは上に戻りません。上部に20pxの空/透明なスペースが残ります。
通常:問題なし
通話中:問題なし
インコールが消えた後:
上部に高さ20ピクセルの空/透明なスペースを残し、下にオレンジ色のビューを表示します。ただし、透明領域の上にはステータスバーがまだ存在しています。ナビゲーションバーには、ステータスバー用のスペースも確保されています。
アプリデリゲートを試してみました:
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)
})
}
私もこの問題に直面しましたが、この方法を適用した後、問題はなくなりました。
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
})
}
このことがあなたのお役に立てば幸いです。
ありがとうございました
私は3日間ソリューションを探していました。私はこの解決策が好きではありませんが、それを修正するより良い方法を見つけませんでした。
RootViewControllerビューの高さがウィンドウよりも20ポイント大きい場合、ステータスバーの高さの更新に関する通知がある場合、手動で正しい値を設定します。
AppDelegate.Swiftにメソッドを追加します
func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
if let window = application.keyWindow {
window.rootViewController?.view.frame = window.frame
}
}
その後、期待どおりに動作します(向きが変わった後でも)。私はこれにあまりにも多くの時間を費やしたので、それが誰かを助けることを願っています。
追伸少し点滅しますが、動作します。
これは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
})
}
}
}
私は、パーソナルホスポットがステータスバーを変更するのと同じ問題を抱えていました。解決策は、ステータスバーフレームの変更に関するシステム通知に登録することです。これにより、レイアウトを更新でき、発生する可能性のあるレイアウトの問題を修正する必要があります。あなたのためにまったく同じように動作するはずの私のソリューションはこれです:
View Controllerで、viewWillAppear
でUIApplicationDidChangeStatusBarFrameNotification
を購読します
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を渡す、参照を保持してレイアウトを変更する、メソッドを持つなど、すべてのコントローラーに対してそれを行う別のクラスを作成することができます自己を削除します。コードを再利用するために知っています。
この問題の解決策を探していました。実際、私はこれに似た新しい質問を投稿しました。ここ: 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)
}
}
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を上から柔軟にするだけです。
私の場合、ViewControllerにカスタムプレゼンテーションスタイルを使用しています。問題は、Y位置が適切に計算されないことです。元の画面の高さが736pであるとします。 view.frame.Origin.y
とview.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()
}
}
コンテナビューに追加した後、表示するView Controllerのビューのフレームをコンテナビューの境界に設定してください。これで問題が解決しました。
containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds