问题:
在通话中状态栏消失后,模态显示的视图控制器不会向上移动,在顶部留下20px空/透明空间。
正常:无问题
待命:无问题
在通话中消失后:
在顶部留下20px高的空/透明空间,露出下面的橙色视图。但是,状态栏仍然存在于透明区域上方。导航栏还为状态栏留出了空间,它的状态栏是只有20px的位置太低。
我试着听App代表:
willChangeStatusBarFrame
didChangeStatusBarFrame
同时查看基于控制器的通知:
UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame
当我记录所有上述四种方法的呈现视图的帧时,帧始终位于(y:0)原点。
查看控制器自定义模式演示文稿
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)
})
}
答案 0 :(得分:5)
我也遇到了这个问题但是在我使用这种方法后,问题就消失了。
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
})
}
希望这件事能对你有所帮助。
答案 1 :(得分:5)
我一直在寻找解决方案3天。我不喜欢这个解决方案,但没有找到更好的解决方法。
当rootViewController视图比窗口高20个点时,我遇到了这种情况,当我收到有关状态栏高度更新的通知时,我手动设置了正确的值。
将方法添加到AppDelegate.swift
func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
if let window = application.keyWindow {
window.rootViewController?.view.frame = window.frame
}
}
之后它按预期工作(即使在方向改变后)。 希望它会对某人有所帮助,因为我花了太多时间在这上面。
P.S。它眨了一下,但是有效。
答案 2 :(得分:3)
我在修改状态栏的人员hospot遇到了同样的问题。 解决方案是注册系统通知以更改状态栏框架,这将允许您更新布局并应修复您可能遇到的任何布局问题。 我的解决方案对你来说应该是完全相同的:
在视图控制器中,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传递给方法,保持引用以更改布局和有一种方法来消除自我。你知道,为了重用代码。
答案 3 :(得分:3)
我认为这是UIKit中的一个错误。当状态栏恢复正常大小时,包含使用自定义转换呈现的呈现控制器视图的containerView
似乎不会完全移回。 (您可以在关闭呼叫状态栏后检查视图层次结构)
要解决此问题,您可以在演示时提供自定义演示控制器。然后,如果您不需要呈现控制器的视图保留在视图层次结构中,您只需返回true
表示控制器的shouldRemovePresentersView
属性,并且&#39是的。
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
})
}
}
}
答案 4 :(得分:3)
我一直在寻找这个问题的解决方案。事实上,我发布了一个与此类似的新问题。这里:How To Avoid iOS Blue Location NavigationBar Messing Up My StatusBar?
相信我,我已经解决了这几天了,因为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)
}
}
答案 5 :(得分:1)
我使用一行代码解决了这个问题
在目标C
tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);
在Swift中
self.tabBarController?.tabBar.autoresizingMask =
UIViewAutoresizing(rawValue: UIViewAutoresizing.RawValue(UInt8(UIViewAutoresizing.flexibleWidth.rawValue) | UInt8(UIViewAutoresizing.flexibleTopMargin.rawValue)))`
您只需要从顶部开始使用tabbar灵活的自动调整功能。
答案 6 :(得分:1)
对于我来说,我正在为ViewController使用自定义表示样式。
问题在于Y位置的计算不正确。
假设原始萤幕高度为736p。
尝试打印view.frame.origin.y
和view.frame.height
,您会发现高度为716p,y为20。
但是显示高度为736-20(通话状态栏额外高度)-20(y位置)。
这就是为什么我们的视图是从ViewController的底部切下的,为什么顶部有20p的空白。
但是,如果您返回查看导航控制器的框架值。
您会发现无论通话状态栏是否显示,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()
}
}
答案 7 :(得分:0)
在将要显示的视图控制器视图的框架添加到容器视图之后,请确保将其设置为容器视图的边界。这为我解决了这个问题。
containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds