5

Durante l'esecuzione di alcune operazioni di rete, presento un controller di visualizzazione modale (simile a MBProgressHUD ma come controller di visualizzazione) per impedire l'interazione dell'utente e indicare lo stato di avanzamento.Presentazione di un controller di visualizzazione senza modificare il colore della barra di stato, come UIAlertController

Il controller di visualizzazione ha modalPresentationStyle = .Custom ed è animato utilizzando un delegato di transizione e un controller di presentazione personalizzato. Oltre ad animare le transizioni, non hanno azioni personalizzate che guidano la presentazione.

Il problema che ho è che ogni volta che viene presentato il controller della vista, il colore della barra di stato diventa nero. Potrei ignorare preferredStatusBarStyle per farlo restituire sempre .LightContent ma a volte questo controller di visualizzazione è presentato su un controller di visualizzazione con .Default e non voglio cambiarlo neanche lì. Fondamentalmente, voglio avere lo stesso comportamento di UIAlertController.

Screenshot showing presented view controller causing dark status bar content

ho cercato di configurare il controller di presentazione per spostare il controller di vista presentato fuori dello spazio barra di stato:

private class SEUIProgressControllerPresentationController: UIPresentationController { 

    override func shouldPresentInFullscreen() -> Bool { 
     return false 
    } 

    private override func frameOfPresentedViewInContainerView() -> CGRect { 
     return super.frameOfPresentedViewInContainerView().insetBy(dx: 40, dy: 100) 
    } 

    ... 
} 

Queste impostazioni fanno muovere la parte superiore del controller presentato fuori dalla barra di stato ma la barra di stato è ancora interessata. C'è una proprietà che mi manca che potrebbe impedire al controller della mia vista di aggiornare lo stile della barra di stato?

risposta

3

Aggiornamento

Sembra che questo è stato risolto in iOS 10. Il comportamento predefinito è quello di ignorare le regole barra di stato del controller di vista presentato a meno sia il controller di vista presentato ha modalPresentationCapturesStatusBarAppearance == true o si utilizza uno dei diversi controller di presentazione incorporati che si estendono nello spazio della barra di stato (non .custom).

Fondamentalmente, il comportamento per l'abitudine è cambiato in opt-out predefinito piuttosto che in opt-in forzato.


Per iOS 9.xe inferiore

Dopo molte scavo, la logica interna per impostare il colore barra di stato dell'applicazione aspetto:

var viewController = window.rootViewController! 

while let presentedViewController = viewController.valueForKey("_presentedStatusBarViewController") as? UIViewController { 
    viewController = presentedViewController 
} 

while let childViewController = viewController.childViewControllerForStatusBarStyle() { 
    viewController = childViewController 
} 

let style = viewController.preferredStatusBarStyle() 

proprietà _presentedStatusBarViewController del controller di vista è assegnato durante la presentazione in base al valore del metodo privato del controller di presentazione _shouldChangeStatusBarViewController(). L'implementazione predefinita di questo metodo è di restituire true, con _UIAlertControllerPresentationController e una manciata di altri controller di presentazione che restituiscono false.

Ciò significa che il modo più diretto per non cambiare la barra di stato è semplicemente di aggiungere questo metodo per il mio controller di presentazione:

private class SEUIProgressControllerPresentationController: UIPresentationController { 

    @objc func _shouldChangeStatusBarViewController() -> Bool { 
     return false 
    } 

    ... 
} 

Purtroppo, questo non passerà una revisione App Store.

Invece, quello che sto facendo è ricreare la logica che sarebbe stato applicato al controller della vista che presenta a mio controller della vista:

public class SEUIProgressController: UIViewController { 

    ... 
    public override func preferredStatusBarStyle() -> UIStatusBarStyle { 

     guard var targetViewController = presentingViewController else { 
      return .LightContent 
     } 

     while let parentViewController = targetViewController.parentViewController { 
      targetViewController = parentViewController 
     } 

     while let childViewController = targetViewController.childViewControllerForStatusBarStyle() { 
      targetViewController = childViewController 
     } 

     return targetViewController.preferredStatusBarStyle() 
    } 

    public override func prefersStatusBarHidden() -> Bool { 

     guard var targetViewController = presentingViewController else { 
      return false 
     } 

     while let parentViewController = targetViewController.parentViewController { 
      targetViewController = parentViewController 
     } 

     while let childViewController = targetViewController.childViewControllerForStatusBarHidden() { 
      targetViewController = childViewController 
     } 

     return targetViewController.prefersStatusBarHidden() 
    } 
}