Подтвердить что ты не робот

Ошибка строки состояния входа в UIViewController

Вопрос:

Модифицированный представленный контроллер представления не перемещается назад после того, как строка состояния в вызове исчезает, оставляя 20px пустым/прозрачным пространством вверху.


Обычный: Нет проблем

введите описание изображения здесь


In-Call: No Issues

введите описание изображения здесь


После вызова In-Call:

Выдает 20px высокое пустое/прозрачное пространство сверху, показывающее оранжевый вид ниже. Однако строка состояния все еще присутствует в прозрачной области. Панель навигации также оставляет место для строки состояния, ее "всего 20 пикселей слишком мало в размещении".

введите описание изображения здесь

введите описание изображения здесь


  • Основанный на iOS 10
  • Модифицированный контроллер представления.
  • Пользовательская модальная презентация
  • Контроллер основного вида оранжевый
  • Не использовать Autolayout
  • При повороте на Пейзаж, 20px In-Call Bar оставляет и все еще оставляет 20px-зазор.
  • Я отказываюсь от отображения строки состояния в ландшафтных ориентациях. (то есть большинство акций)

Я попробовал прослушивать App Delegates:

willChangeStatusBarFrame
didChangeStatusBarFrame

Также просматривать уведомления на основе контроллера:

UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame

Когда я регистрирую фрейм представленного представления для всех четырех вышеописанных методов, кадр всегда находится в начале (y: 0).


Update

Просмотр пользовательского модального представления контроллера

    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)

        })
 }
4b9b3361

Ответ 1

Я тоже столкнулся с этой проблемой, но после того, как я поставил этот метод, проблема исчезла.

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

Надеюсь, эта вещь вам поможет.
Спасибо

Ответ 2

Я искал решение в течение 3 дней. Мне не нравится это решение, но я не нашел лучшего способа как это исправить.

У меня возникает ситуация, когда представление rootViewController имеет большую высоту на 20 точек, чем окно, когда я получаю уведомление об обновлениях высоты строки состояния, я вручную устанавливаю правильное значение.

Добавить метод в AppDelegate.swift

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

После этого он работает как положено (даже после изменения ориентации). Надеюсь, это кому-нибудь поможет, потому что я потратил слишком много времени на это.

PS Немного мигает, но работает.

Ответ 3

У меня была та же проблема с персональным хостом, который менял строку состояния. Решением является регистрация системного уведомления для изменения рамки строки состояния, это позволит вам обновить макет и исправить любую проблему с макетом, которая может возникнуть. Мое решение, которое должно работать точно так же для вас, следующее:

  • В вашем представлении контроллер, в 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 перед представлением представления.

Вы можете реализовать это на каждом контроллере, подверженном изменениям в строке состояния, или вы можете сделать другой класс, который будет делать это для каждого контроллера, например, передать себя методу, сохранить ссылку для изменения макета и есть способ удалить себя. Вы знаете, для повторного использования кода.

Ответ 4

Я думаю, что это ошибка в 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
            })
        }
    }
}

Ответ 5

Я искал решение этой проблемы. На самом деле я разместил новый вопрос, похожий на этот. Здесь: Как избежать iOS Blue Location NavigationBar испортить мой StatusBar?

Поверьте мне, я решаю эту проблему уже пару дней, и это действительно раздражает, когда ваш экран портится из-за изменений строки состояния iOS по входящему вызову, точке доступа и местоположению.

Я попытался реализовать ответ Моди, я поместил этот кусок кода в свой AppDelegate и немного его изменил, но не повезло. и я считаю, что iOS делает это автоматически, так что вам не придется реализовывать это самостоятельно.

Прежде чем я обнаружил виновника проблемы, я попробовал каждое решение в этом конкретном вопросе. Нет необходимости реализовывать метод willChangeStatusBar... или добавлять уведомления для наблюдения за изменениями statusBar.

Я также переделал некоторые потоки моего проекта, выполнив некоторые экраны программно (я использую раскадровки). И я немного поэкспериментировал, затем проверил мои предыдущие и другие текущие проекты, почему они делают корректировку правильно :)

Итог: я представляю свой главный экран с UITabBarController таким неправильным образом.

Пожалуйста, всегда modalPresentationStyle внимание на 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)
    }
}

Ответ 6

Я решаю эту проблему, используя одну строку кода

В цели C

tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);

В Свифте

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

Вам просто нужно сделать autoresizingMask из tabBar гибким сверху.

Ответ 7

Обязательно установите рамку представления контроллера представления, которое вы представляете, в границы представления контейнера, после того, как оно было добавлено в представление контейнера. Это решило проблему для меня.

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

Ответ 8

В моем случае я использую собственный стиль представления для моего ViewController. Проблема в том, что позиция Y не рассчитана хорошо. Допустим, оригинальная высота экрана составляет 736p. Попробуйте напечатать view.frame.origin.y и view.frame.height, вы увидите, что высота равна 716p, а y равно 20. Но высота дисплея составляет 736 - 20 (дополнительная высота строки состояния вызова) - 20 (позиция у). Вот почему наше представление вырезано из нижней части ViewController и почему в верхней части есть отступ в 20 пунктов. Но если вы вернетесь, чтобы увидеть значение кадра контроллера навигации. Вы обнаружите, что независимо от того, отображается строка состояния вызова или нет, позиция 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()
    }
}

Ответ 9

Это мило

Тем временем ответьте на 5 вопросов правильно, чтобы выиграть 50 долларов

Все вопросы на

https://www.skbase.blogspot.com

если вы попытаетесь ответить на несколько вопросов, вам также будет вручен небольшой приз

укажите свой адрес электронной почты, чтобы связаться с вами