wake-up-neo.com

Problem mit der UIViewController-Statusleiste während des Anrufs

Problem:

Modal präsentierte Ansichtssteuerung bewegt sich nicht nach oben, wenn die Statusleiste während eines Anrufs nicht mehr angezeigt wird, sodass oben 20px leerer/transparenter Bereich verbleibt.


Normal: Keine Probleme

 enter image description here


In-Call: Keine Probleme

 enter image description here


Nach dem Anruf verschwindet:

Hinterlässt oben einen 20px hohen leeren/transparenten Bereich, der die orange Ansicht unten freigibt. Die Statusleiste befindet sich jedoch weiterhin im transparenten Bereich. Die Navigationsleiste lässt auch Platz für die Statusleiste, deren Platzierung um nur 20 Pixel zu niedrig ist.

 enter image description here

 enter image description here


  • iOS 10 basiert 
  • Modal präsentierter View Controller 
  • Kundenspezifische modale Präsentation
  • Der Main View Controller dahinter ist orange
  • Autolayout nicht verwenden
  • Bei einer Drehung zu Landscape verlässt die 20px-In-Call-Leiste immer noch eine Lücke von 20px.
  • Ich lehne die Anzeige der Statusleiste in Querformat ab. (dh die meisten Apps auf Lager)

Ich habe versucht, App-Delegierten zuzuhören:

willChangeStatusBarFrame
didChangeStatusBarFrame

Controller-basierte Benachrichtigungen anzeigen:

UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame

Wenn ich den Frame der dargestellten Ansicht für alle vier oben genannten Methoden protokolliere, befindet sich der Frame immer in (y: 0) Origin.


Aktualisieren

View Controller Custom Modal Präsentation

    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

Ich war auch mit diesem Problem konfrontiert, aber nachdem ich diese Methode eingesetzt habe, ist das Problem weg.

iOS hat seine Standardmethode willChangeStatusBarFrame für die Statusleiste. Bitte setzen Sie diese Methode ein und überprüfen Sie sie. 

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

Ich hoffe, dieses Ding wird dir helfen.
Vielen Dank

4
Jitendra Modi

Ich habe seit 3 ​​Tagen nach einer Lösung gesucht. Ich mag diese Lösung nicht, habe aber keine bessere Lösung gefunden.

In der Situation, in der die rootViewController-Ansicht für 20 Punkte eine höhere Höhe aufweist als für das Fenster, wird die Höhe der Statusleiste aktualisiert, und ich stelle den korrekten Wert manuell ein.

Fügen Sie der AppDelegate.Swift eine Methode hinzu

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

Danach funktioniert es wie erwartet (auch nach Orientierungsänderungen) . Ich hoffe es hilft jemandem, weil ich zu viel Zeit damit verbracht habe.

P.S. Es blinkt ein bisschen, funktioniert aber.

4
Bws Sluk

Ich denke, das ist ein Fehler in UIKit. Die containerView, die die Ansicht eines dargestellten Controllers enthält, die mit einem benutzerdefinierten Übergang dargestellt wurde, scheint sich nicht vollständig zurückzubewegen, wenn die Statusleiste wieder ihre normale Größe annimmt. (Sie können die Ansichtshierarchie überprüfen, nachdem Sie die Anrufstatusleiste geschlossen haben.)

Um dies zu lösen, können Sie beim Präsentieren einen benutzerdefinierten Präsentationscontroller bereitstellen. Und wenn Sie nicht die Ansicht des präsentierenden Controllers benötigen, um in der Ansichtshierarchie zu verbleiben, können Sie einfach true für die shouldRemovePresentersView-Eigenschaft des Präsentationscontrollers zurückgeben.

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

wenn die Ansicht des präsentierenden Controllers erhalten bleiben soll, können Sie die Änderung des Statusleistenrahmens beobachten und die Variable containerView manuell auf dieselbe Größe wie ihr Superview einstellen

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

Ich hatte das gleiche Problem mit dem Personalhospot, der die Statusleiste änderte .. Die Lösung besteht darin, sich bei der Systembenachrichtigung für die Änderung des Statusleistenrahmens zu registrieren. Dadurch können Sie Ihr Layout aktualisieren und sollten eventuell auftretende Layoutprobleme beheben habe . Meine Lösung, die für Sie genauso funktionieren sollte, lautet:

  • In Ihrem View-Controller in viewWillAppear die UIApplicationDidChangeStatusBarFrameNotification verwenden

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(myControllerName.handleFrameResize(_:)), name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • Erstellen Sie Ihre Auswahlmethode 

    func handleFrameResize(notification: NSNotification) {
    self.view.layoutIfNeeded() }
    
  • Entfernen Sie Ihren Controller aus dem Benachrichtigungscenter in viewWillDisappear.

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
    
  • Ihr Modal muss auch für die Statusleiste verantwortlich sein, damit Sie die Einstellung vornehmen können 

    destVC.modalPresentationCapturesStatusBarAppearance = true bevor die Ansicht präsentiert wird.

Sie können dies entweder auf jedem Controller implementieren, der anfällig für eine Änderung in der Statusleiste ist, oder Sie können eine andere Klasse erstellen, die dies für jeden Controller ausführt, z. B. das Weitergeben an eine Methode. Behalten Sie den Verweis bei, um das Layout zu ändern, und verwenden Sie eine Methode Selbst entfernen Sie wissen, um Code wiederzuverwenden.

3
thibaut noah

Ich habe nach einer Lösung für dieses Problem gesucht. In der Tat habe ich eine neue Frage ähnlich dieser gestellt. Hier: Wie vermeide ich iOS Blue Location NavigationBar Meine Statusleiste durcheinanderbringen?

Glauben Sie mir, ich habe das jetzt schon ein paar Tage gelöst, und es ist wirklich ärgerlich, dass Ihr Bildschirm durch die Statusleiste der iOS-Statusleiste je nach Anruf, Hotspot und Standort beschädigt wurde.

Ich habe versucht, die Antwort von Modi zu implementieren. Ich habe diesen Code in meine AppDelegate eingefügt und etwas modifiziert, aber kein Glück. Ich glaube, iOS macht das automatisch, sodass Sie das nicht selbst implementieren müssen.

Bevor ich den Schuldigen des Problems entdeckte, habe ich in dieser speziellen Frage jede Lösung ausprobiert. Sie müssen die AppDelegate-Methode willChangeStatusBar... nicht implementieren oder eine Benachrichtigung hinzufügen, um StatusBar-Änderungen zu beobachten.

Ich habe auch einige der Flüsse meines Projekts überarbeitet, indem ich einige Bildschirme programmatisch durchführte (ich verwende Storyboards). Und ich experimentierte ein wenig und inspizierte dann meine vorherigen und anderen aktuellen Projekte, warum sie die Anpassung richtig vornehmen :)

Bottom line is: Ich präsentiere meinen Hauptbildschirm mit UITabBarController auf eine so falsche Weise.

Bitte beachten Sie immer die modalPresentationStyle. Ich hatte die Idee, meinen Code wegen Noahs Kommentar zu überprüfen. 

Probe:

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

Ich löse dieses Problem mit einer Codezeile

In Ziel C

tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);

In Swift

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

Sie müssen nur die AutoresizingMask von tabBar von oben flexibel gestalten.

1
Sahil_Saini

In meinem Fall verwende ich einen benutzerdefinierten Präsentationsstil für meinen ViewController. Das Problem ist, dass die Y-Position nicht gut berechnet wird. Angenommen, die ursprüngliche Bildschirmhöhe beträgt 736p. Versuchen Sie, das view.frame.Origin.y und view.frame.height, Sie werden feststellen, dass die Höhe 716p und das y 20 beträgt. Die Anzeigehöhe beträgt jedoch 736 - 20 (zusätzliche Höhe der Statusleiste für eingehende Anrufe) - 20 (Position y). Das ist der Grund, warum unsere Ansicht vom unteren Rand des ViewControllers abgeschnitten wird und warum es einen 20p-Rand nach oben gibt. Wenn Sie jedoch zurückgehen, wird der Frame-Wert des Navigationscontrollers angezeigt. Sie werden feststellen, dass die y-Position immer 0 ist, unabhängig davon, ob die Statusleiste für eingehende Anrufe angezeigt wird oder nicht.

Also müssen wir nur die y-Position auf Null setzen.

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

Stellen Sie sicher, dass der Frame der Ansichts-Controller-Ansicht, die Sie anzeigen, an die Grenzen der Containeransicht angepasst wird, nachdem er der Containeransicht hinzugefügt wurde. Dies löste das Problem für mich.

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