swift UIViewController呼叫中状态栏问题

ikfrs5lh  于 5个月前  发布在  Swift
关注(0)|答案(8)|浏览(41)

问题:

模态呈现的视图控制器在呼叫状态栏消失后不会向上移动,在顶部留下20 px的空白/透明空间。

正常:无问题

x1c 0d1x的数据

来电:无问题


来电消失后:

在顶部留下一个20像素高的空白/透明空间,显示下面的橙子视图。然而,状态栏仍然存在于透明区域。导航栏也为状态栏留下空间,它的位置太低了。


  • 基于iOS 10
  • 模态呈现的视图控制器
  • 自定义模态演示
  • 后面的主视图控制器为橙子
  • 不使用自动布局
  • 当旋转到横向时,20 px的呼叫酒吧离开,仍然留下20 px的间隙。
  • 我选择退出横向显示状态栏。(即大多数股票应用程序)

我试着去听App Delegates:

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)

        })
 }

o4hqfura

o4hqfura1#

我一直在寻找一个解决方案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.它会 Flink 一点,但很有效。

ehxuflar

ehxuflar2#

我也遇到过这个问题,但我用了这个方法后,问题就消失了。
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
    })
}

字符串

ddhy6vgd

ddhy6vgd3#

我也有同样的问题与personnal 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传递给一个方法,保留引用来改变布局,并有一个方法来删除self。你知道,为了重用代码。

mbskvtky

mbskvtky4#

我认为这是UIKit中的一个bug。当状态栏恢复正常大小时,包含使用自定义转换呈现的控制器视图的containerView似乎没有完全向后移动。(您可以在关闭调用状态栏后检查视图层次结构)
为了解决这个问题,你可以在演示时提供一个自定义的演示控制器。然后如果你不需要演示控制器的视图保持在视图层次结构中,你可以只返回true for shouldRemovePresentersView property of the presentation controller,就是这样。

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
            })
        }
    }
}

yacmzcpb

yacmzcpb5#

我一直在寻找这个问题的解决方案。事实上,我发布了一个类似的新问题。这里:如何避免iOS蓝色位置导航栏弄乱我的状态栏?
相信我,我已经解决这个问题几天了,你的屏幕被弄得一团糟真的很烦人,因为iOS的状态栏会因为通话、热点和位置而改变。
我试过实现Modi的答案,我把这段代码放在我的AppDelegate中,并修改了一下,但没有运气。我相信iOS会自动完成,所以你不必自己实现。
在我发现问题的罪魁祸首之前,我确实尝试了这个特定问题的每一种解决方案。不需要实现AppDelegate的方法willChangeStatusBar...或添加通知来观察statusBar的变化。
我也做了重做我的项目的一些流程,通过编程做一些屏幕(我使用故事板)。我做了一点实验,然后检查了我以前和其他当前的项目,为什么他们做了正确的调整:)

底线是:我以错误的方式呈现了我的主屏幕和PullabBarController。

请始终注意modalPresentationStyle。由于Noah的评论,我有了检查我的代码的想法。
样品名称:

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)
    }
}

字符串

eanckbw9

eanckbw96#

我用一行代码解决了这个问题

在Objective C中

tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);

字符串

在Swift

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


你只需要让tabBar的autoresizingMask从顶部灵活。

ybzsozfc

ybzsozfc7#

在我的例子中,我为我的ViewController使用自定义演示样式。问题是Y位置计算不好。假设原始屏幕高度为736 p。尝试打印view.frame.origin.yview.frame.height,你会发现高度是716 p,y是20。但是显示高度是736 - 20(通话中状态栏额外高度)- 20(y位置)。这就是为什么我们的视图是从ViewController的底部剪切的,也是为什么顶部有20 p的边距。但是如果你回去看看导航控制器的frame值。你会发现无论呼叫中状态栏是否显示,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()
    }
}

字符串

7kqas0il

7kqas0il8#

在将视图控制器的视图添加到容器视图之后,确保将视图控制器的视图框架设置为容器视图的边界。

containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds

字符串

相关问题