ios - example - alamofire get
Problema de la barra de estado de llamadas entrantes de UIViewController (8)
Problema:
El controlador de vista presentado modalmente no retrocede una vez que desaparece la barra de estado durante la llamada, dejando un espacio vacío / transparente de 20 px en la parte superior.
Normal: sin problemas
En llamada: sin problemas
Después de que desaparezca la llamada:
Deja un espacio vacío / transparente de 20 px de alto en la parte superior que revela una vista naranja debajo. Sin embargo, la barra de estado todavía está presente sobre el área transparente. La barra de navegación también deja espacio para la barra de estado, solo tiene 20 píxeles de ubicación demasiado baja.
- basado en iOS 10
- Controlador de vista presentado modalmente
- Presentación modal personalizada
- El controlador de vista principal detrás es naranja
- No usar Autolayout
- Cuando se gira a horizontal , la barra de llamadas entrantes de 20 píxeles deja y aún deja un espacio de 20 píxeles.
- Opto por no mostrar la barra de estado en orientaciones horizontales. (es decir, la mayoría de las aplicaciones de stock)
Traté de escuchar a los delegados de la aplicación:
willChangeStatusBarFrame
didChangeStatusBarFrame
Ver también las notificaciones basadas en el controlador:
UIApplicationWillChangeStatusBarFrame
UIApplicationDidChangeStatusBarFrame
Cuando registro el marco de la vista presentada para los cuatro métodos anteriores, el marco siempre está en el origen (y: 0).
Actualizar
Ver presentación modal personalizada del controlador
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)
})
}
Asegúrese de establecer el marco de la vista del controlador de vista que está presentando en los límites de la vista del contenedor, después de que se haya agregado a la vista del contenedor. Esto resolvió el problema para mí.
containerView.addSubview(toViewController.view)
toViewController.view.frame = containerView.bounds
Creo que esto es un error en UIKit.
El
containerView
que contiene la vista de un controlador presentado que se presentó utilizando una transición personalizada no parece retroceder por completo cuando la barra de estado vuelve al tamaño normal.
(Puede verificar la jerarquía de la vista después de cerrar la barra de estado de la llamada)
Para resolverlo, puede proporcionar un controlador de presentación personalizado al presentar.
Y luego, si no necesita que la vista del controlador de presentación permanezca en la jerarquía de vistas, puede devolver
true
para la propiedad
shouldRemovePresentersView
del controlador de presentación, y eso es todo.
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
}
}
o si necesita que la vista del controlador actual permanezca, puede observar el cambio en el marco de la barra de estado y ajustar manualmente
containerView
para que tenga el mismo tamaño que su supervista
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
})
}
}
}
En mi caso, estoy usando un estilo de presentación personalizado para mi ViewController.
El problema es que la posición Y no se calcula bien.
Digamos que la altura de la pantalla original es de 736p.
Intente imprimir
view.frame.origin.y
y
view.frame.height
, encontrará que la altura es 716p y la y es 20. Pero la altura de la pantalla es 736 - 20 (altura adicional de la barra de estado en llamada) 20 (posición y).
Es por eso que nuestra vista se corta desde la parte inferior del ViewController y por qué hay un margen de 20p en la parte superior.
Pero si regresa para ver el valor de cuadro del controlador de navegación.
Descubrirá que no importa si se muestra o no la barra de estado durante la llamada, la posición y siempre es 0.
Entonces, todo lo que tenemos que hacer es establecer la posición y en cero.
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()
}
}
He estado buscando una solución a este problema. De hecho, publiqué una nueva pregunta similar a esta. Aquí: ¿Cómo evitar la barra de navegación de ubicación azul de iOS?
Créame, he estado resolviendo esto durante un par de días y es realmente molesto tener su pantalla en mal estado debido a los cambios en la barra de estado del iOS por llamada entrante, punto de acceso y ubicación.
Intenté implementar la respuesta de Modi, puse ese fragmento de código en mi AppDelegate y lo modifiqué un poco, pero no tuve suerte. y creo que iOS lo hace automáticamente para que no tenga que implementarlo usted mismo.
Antes de descubrir al culpable del problema, probé cada solución en esta pregunta en particular.
No es necesario implementar el método de AppDelegate
willChangeStatusBar...
o agregar una notificación para observar los cambios de statusBar.
También rehice algunos de los flujos de mi proyecto, haciendo algunas pantallas mediante programación (estoy usando guiones gráficos). Y experimenté un poco, luego inspeccioné mis proyectos anteriores y otros actuales por qué están haciendo el ajuste correctamente :)
La conclusión es : estoy presentando mi pantalla principal con UITabBarController de manera incorrecta.
Siempre tenga en cuenta el
modalPresentationStyle
.
Tuve la idea de revisar mi código debido al comentario de Noah.
Muestra:
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)
}
}
He estado buscando una solución durante 3 días. No me gusta esta solución, pero no encontré una mejor manera de solucionarla.
Tengo una situación en la que la vista rootViewController tiene una altura mayor para 20 puntos que la ventana, cuando recibo una notificación sobre las actualizaciones de altura de la barra de estado, configuro manualmente el valor correcto.
Agregar método a AppDelegate.swift
func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
if let window = application.keyWindow {
window.rootViewController?.view.frame = window.frame
}
}
Después de eso funciona como se esperaba (incluso después de los cambios de orientación). Espero que ayude a alguien, porque pasé demasiado tiempo en esto.
PD: Parpadea un poco, pero funciona.
Resuelvo este problema usando una línea de código
En el objetivo C
tabBar.autoresizingMask = (UIViewAutoResizingFlexibleWidth | UIViewAutoResizingFlexibleTopMargin);
En veloz
self.tabBarController?.tabBar.autoresizingMask =
UIViewAutoresizing(rawValue: UIViewAutoresizing.RawValue(UInt8(UIViewAutoresizing.flexibleWidth.rawValue) | UInt8(UIViewAutoresizing.flexibleTopMargin.rawValue)))`
Solo tiene que hacer que autoresizingMask de tabBar sea flexible desde la parte superior.
También enfrenté este problema, pero después de poner este método, el problema desapareció.
iOS tiene su método predeterminado
willChangeStatusBarFrame
para manejar la barra de estado.
Por favor, ponga este método y verifíquelo.
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
})
}
Espero que esto te ayude.
Gracias
Tuve el mismo problema con el hospot personal modificando la barra de estado. La solución es registrarse en la notificación del sistema para el cambio del marco de la barra de estado, esto le permitirá actualizar su diseño y debería solucionar cualquier problema de diseño que pueda tener. Mi solución que debería funcionar exactamente igual para usted es esta:
-
En su controlador de vista, en
viewWillAppear
a laUIApplicationDidChangeStatusBarFrameNotification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(myControllerName.handleFrameResize(_:)), name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
-
Crea tu método selector
func handleFrameResize(notification: NSNotification) { self.view.layoutIfNeeded() }
-
Retire su controlador del centro de notificaciones en
viewWillDisappear
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidChangeStatusBarFrameNotification, object: nil)
-
También necesita su modal para estar a cargo de la barra de estado, por lo que debe configurar
destVC.modalPresentationCapturesStatusBarAppearance = true
antes de presentar la vista.
Puede implementar esto en cada controlador susceptible de tener un cambio en la barra de estado, o puede hacer otra clase que lo haga para cada controlador, como pasar a un método, mantener la referencia para cambiar el diseño y tener un método quitarse a uno mismo. Ya sabes, para reutilizar el código.