ios - not - hide status bar swift 4
Barra de estado de la llamada(no se pueden satisfacer las restricciones) (4)
Todo lo anterior no parecía soluciones simples. Me encontré con el mismo problema cuando agregué la subvista en viewDidLoad. Lo resolví moviendo el código a la vistaDidAppear. FYI.
Al igual que esta pregunta: Diseño automático y barra de estado en llamada y esta pregunta: ¿ Cambiar el tamaño para la barra de estado en llamada? , Tengo problemas con la barra de estado de llamadas entrantes que arruina mi diseño de vista.
Aquí está mi estructura anidada. Tengo un ViewController modal personalizado que está anidado dentro de otro ViewController. Cada vez que se muestra la barra de estado de llamada entrante (y luego se cierra), esto es lo que sucede:
Aquí hay una imagen de cómo debería verse antes de que se muestre la barra de estado de llamada:
El color de fondo azul de la barra de estado después de que ocurra el error es el color de fondo del controlador de vista raíz.
Cada vez que se muestra una barra de estado de llamada entrante, se imprime el siguiente error:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don''t want. Try this: (1) look at each constraint and try to figure out which you don''t expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you''re seeing NSAutoresizingMaskLayoutConstraints that you don''t understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fdac6192320 V:|-(20)-[UIInputSetContainerView:0x7fdac6190a40] (Names: ''|'':UITextEffectsWindow:0x7fdac6061a10 )>",
"<NSLayoutConstraint:0x7fdac608ebb0 ''UIInputWindowController-top'' V:|-(0)-[UIInputSetContainerView:0x7fdac6190a40] (Names: ''|'':UITextEffectsWindow:0x7fdac6061a10 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fdac6192320 V:|-(20)-[UIInputSetContainerView:0x7fdac6190a40] (Names: ''|'':UITextEffectsWindow:0x7fdac6061a10 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don''t want. Try this: (1) look at each constraint and try to figure out which you don''t expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you''re seeing NSAutoresizingMaskLayoutConstraints that you don''t understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7fc60b03d230 V:|-(20)-[UIInputSetContainerView:0x7fc608d22020] (Names: ''|'':UITextEffectsWindow:0x7fc60b171720 )>",
"<NSLayoutConstraint:0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>",
"<NSLayoutConstraint:0x7fc60b17c4b0 ''UIInputWindowController-height'' UIInputSetContainerView:0x7fc608d22020.height == UITextEffectsWindow:0x7fc60b171720.height>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fc60b03d2d0 UIInputSetContainerView:0x7fc608d22020.bottom == UITextEffectsWindow:0x7fc60b171720.bottom>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Usando la herramienta de depuración FLEX puedo ver que
UINavigationBarBackground
y
UIStatusBarForegroundView
superponen antes de la barra de estado de la llamada
UINavigationBarBackground
, sin embargo, después
UINavigationBarBackground
está debajo de
UIStatusBarForegroundView
Este error solo ocurre DESPUÉS de presentar el controlador de vista modal. Si muestro la barra de estado en llamada, entonces el problema no ocurre. No puede volver al controlador de vista raíz después de que se muestre el controlador de vista modal.
¿Qué puedo hacer para arreglar esto?
Un problema similar también se puede encontrar aquí: https://forums.developer.apple.com/thread/20632
Intenté la solución sugerida de ese tema implementando el fragmento a continuación en mi AppDelegate. Parece deshacerse de los errores de restricción, pero soy muy reacio a lanzar una aplicación con esto, ya que sin duda es un Apple Bug.
Pasos para reproducir:
- Cree una nueva aplicación de vista única en Xcode 7.1
- Ejecute la aplicación en un simulador de iOS 9.1
- Alternar la barra de llamadas entrantes (CMD + Y)
- Verá "No se puede satisfacer simultáneamente las restricciones". error.
Para deshacerse del error de restricción:
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame {
for(UIWindow *window in [[UIApplication sharedApplication] windows])
{
if([window.class.description isEqual:@"UITextEffectsWindow"])
{
[window removeConstraints:window.constraints];
}
}
}
Personalmente, solo utilicé el fragmento anterior para asegurarme de que los errores de restricción no estaban causando otros problemas de restricción que tenía, a saber: pantallas negras cuando la aplicación se lanzó en segundo plano. Que resultó no ser el caso.
Versión rápida de la respuesta @matty:
func application(application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect) {
for window in UIApplication.sharedApplication().windows {
if window.dynamicType.self.description().containsString("UITextEffectsWindow") {
window.removeConstraints(window.constraints)
}
}
}
iOS 9.2.1, Xcode 7.2.1, ARC habilitado
ACTUALIZACIÓN 25/03/2016: El conflicto todavía existe en Xcode 7.3, iOS 9.3.
Resumen:
en la jerarquía de ventanas de su aplicación, hay varias ventanas que se agregan a la ventana de la aplicación.
En mi caso, este fue
UITextEffectsWindow
y
UIRemoteKeyboardWindow
.
Estas ventanas vienen con restricciones preconfiguradas.
Parece que hay un error que actualiza algunas restricciones de diseño vertical, pero no otras restricciones relacionadas para la misma ventana.
Esto arroja el conflicto de restricciones en el depurador.
Esto sucede cuando se agrega una ventana personalizada a la jerarquía de la ventana o cuando la barra de estado de llamada entrante se activa o desactiva, tanto en el simulador como en el dispositivo iOS real.
Las restricciones son prioridad 1000, esto indica que son restricciones requeridas.
La solución a continuación eliminará la restricción conflictiva y la agregará nuevamente una vez que se desactive la barra de estado durante la llamada.
EDITAR 25/02/2016: ninguna de las soluciones resuelve el problema de que ya se muestre la barra de estado durante la llamada al abrir la aplicación. El conflicto ocurre antes de que se registre el cambio en la barra de estado.
Parece que este conflicto de restricción ocurre solo la primera vez que se muestra la barra de estado durante la llamada (esto es lo más común), o en otros escenarios que involucran la presentación de una ventana personalizada adicional que se ubicaría en la parte superior de la ventana clave. También intenté crear una aplicación de vista única en blanco y sin agregar nada en la barra de estado de la llamada, y obtuve el mismo conflicto de restricciones.
Creo que es un error y se discute en los foros de desarrollo. El artículo original de los foros de desarrollo se puede encontrar aquí (como señaló matty):
https://forums.developer.apple.com/thread/16375
Quería ampliar un poco la respuesta de Matty aquí . Lo cual me pareció muy útil. No estoy seguro de qué impacto eliminaría "todas" las restricciones, por lo que eliminé solo las restricciones en conflicto. Mi razonamiento es que la restricción conflictiva se romperá de todos modos ya que el depurador informa "Intentará recuperarse rompiendo la restricción" ; entonces la restricción no servirá para nada de todos modos.
Aquí están los errores de conflicto de restricciones que estaba recibiendo:
Después de interpretar los errores de restricción (consulte este documento de Apple para ayudar con eso: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html ) https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html el siguiente código para deshacerme de las restricciones en conflicto:
C objetivo:
* AppDelegate.h
...
@interface YourAppName : UIResponder <UIApplicationDelegate>
{
NSMutableDictionary *dictionaryConstraints;
}
...
* AppDelegate.m
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
dictionaryConstraints = [[NSMutableDictionary alloc] init];
return true;
}
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
NSLog(@"newStatusBarFrame: %@", NSStringFromCGRect(newStatusBarFrame));
if (newStatusBarFrame.size.height > 20.0)
{
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
{
NSMutableArray *constraints = [[NSMutableArray alloc] initWithCapacity:[window.constraints count]];
for (NSLayoutConstraint *constraint in window.constraints)
{
if (!([constraint.description rangeOfString:@"V:|-(0)-[UIInputSetContainerView"].location == NSNotFound))
{
NSLog(@"");
NSLog(@"%@: %@, %f, %f", window.class.description, constraint.description, constraint.priority, constraint.constant);
NSLog(@"");
[constraints addObject:constraint];
[window removeConstraint:constraint];
}
else
{
nil;
}
}
if ([constraints count] > 0)
{
[dictionaryConstraints setObject:constraints forKey:[NSString stringWithFormat:@"%p", window]];
}
else
{
nil;
}
}
else
{
nil;
}
}
}
else
{
nil;
}
}
- (void)resetConstraints
{
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
{
if (dictionaryConstraints)
{
NSArray *keys = [dictionaryConstraints allKeys];
for (int i = 0; i < [keys count]; i++)
{
if ([[NSString stringWithFormat:@"%p", window] isEqualToString:keys[i]])
{
[window addConstraints:[dictionaryConstraints objectForKey:keys[i]]];
}
else
{
nil;
}
}
}
else
{
nil;
}
}
else
{
nil;
}
}
}
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
NSLog(@"oldStatusBarFrame: %@", NSStringFromCGRect(oldStatusBarFrame));
if (oldStatusBarFrame.size.height > 20.0)
{
if ([dictionaryConstraints count] > 0)
{
[self resetConstraints];
[dictionaryConstraints removeAllObjects];
}
else
{
nil;
}
}
else
{
nil;
}
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if ([window.class.description isEqual:@"UITextEffectsWindow"] || [window.class.description isEqual:@"UIRemoteKeyboardWindow"])
{
for (NSLayoutConstraint *constraint in window.constraints)
{
if (!([constraint.description rangeOfString:@"V:|-(0)-[UIInputSetContainerView"].location == NSNotFound))
{
NSLog(@"");
NSLog(@"%@: %@, %f, %f", window.class.description, constraint.description, constraint.priority, constraint.constant);
NSLog(@"");
}
else
{
nil;
}
}
}
else
{
nil;
}
}
}
...
Rápido:
* AppDelegate.swift
...
var dictionaryConstraints = [NSString : NSArray]();
...
func application(application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect)
{
print("newStatusBarFrame: /(newStatusBarFrame)")
if newStatusBarFrame.size.height > 20.0
{
for window in UIApplication.sharedApplication().windows
{
if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
{
var constraints = [NSLayoutConstraint]()
for constraint in window.constraints
{
if (constraint.description.containsString("V:|-(0)-[UIInputSetContainerView"))
{
print("/(window.classForCoder.debugDescription), /(constraint.description), /(constraint.priority), /(constraint.constant)")
constraints.append(constraint)
window.removeConstraint(constraint)
}
else
{
//nil
}
}
if (constraints.count > 0)
{
dictionaryConstraints[NSString(format: "%p", unsafeAddressOf(window))] = constraints
}
else
{
//nil
}
}
else
{
//nil
}
}
}
else
{
//nil
}
}
func resetConstraints()
{
for window in UIApplication.sharedApplication().windows
{
if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
{
if (dictionaryConstraints.count > 0)
{
let keys = Array(dictionaryConstraints.keys)
for i in 0 ..< keys.count
{
if (NSString(format: "%p", unsafeAddressOf(window)) == keys[i])
{
window.addConstraints(dictionaryConstraints[keys[i]] as! [NSLayoutConstraint])
}
else
{
//nil
}
}
}
else
{
//nil
}
}
else
{
//nil
}
}
}
func application(application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect)
{
print("oldStatusBarFrame: /(oldStatusBarFrame)")
if (oldStatusBarFrame.size.height > 20.0)
{
if (dictionaryConstraints.count > 0)
{
self.resetConstraints()
dictionaryConstraints.removeAll()
}
else
{
//nil
}
}
else
{
//nil
}
for window in UIApplication.sharedApplication().windows
{
if ((window.classForCoder.description() == "UITextEffectsWindow") || (window.classForCoder.description() == "UIRemoteKeyboardWindow"))
{
for constraint in window.constraints
{
if (constraint.description.containsString("V:|-(0)-[UIInputSetContainerView"))
{
print("/(window.classForCoder.debugDescription), /(constraint.description), /(constraint.priority), /(constraint.constant)")
}
else
{
//nil
}
}
}
else
{
//nil
}
}
}
...
Nota: Esto mantiene todas las restricciones que no están en conflicto. Y agrega las restricciones conflictivas eliminadas nuevamente después de que la situación conflictiva ya no existe, es decir, la barra de estado de llamada está desactivada.
ACTUALIZACIÓN 25/02/2015: Pruebas adicionales ...
Decidí aislar las restricciones cambiantes usando dos métodos en la aplicación. delegar archivo * .m:
...
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
NSLog(@"New status bar frame: %@", NSStringFromCGRect(newStatusBarFrame));
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
NSLog(@"%@, %@", window.description, window.constraints);
}
}
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame
{
NSLog(@"Old status bar frame: %@", NSStringFromCGRect(oldStatusBarFrame));
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
NSLog(@"%@, %@", window.description, window.constraints);
}
}
...
Cuando la barra de estado durante la llamada se activa, las restricciones en conflicto cambian de:
UITextEffectsWindow:
<UITextEffectsWindow: 0x7fbf994cc810; marco = (0 0; 320 568); opaco = NO; autoresize = W + H; layer = <UIWindowLayer: 0x7fbf994c8470>>,
("<NSLayoutConstraint: 0x7fbf99667eb0 V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido
"<NSLayoutConstraint: 0x7fbf9966c800 ''UIInputWindowController-top'' V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido )
UIRemoteKeyboardWindow:
<UIRemoteKeyboardWindow: 0x7fbf994ceb80; marco = (0 0; 320 568); opaco = NO; autoresize = W + H; layer = <UIWindowLayer: 0x7fbf994cf190>>,
("<NSLayoutConstraint: 0x7fbf994cfb20 V: | - (0) - [UIInputSetContainerView: 0x7fbf99744ec0] (Nombres: ''|'': UIRemoteKeyboardWindow: 0x7fbf994ceb80)>",
... omitido
"<NSLayoutConstraint: 0x7fbf9966c800 ''UIInputWindowController-top'' V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido )
... y cambia a:
UITextEffectsWindow:
<UITextEffectsWindow: 0x7fbf994cc810; marco = (0 0; 320 568); opaco = NO; autoresize = W + H; layer = <UIWindowLayer: 0x7fbf994c8470>>,
("<NSLayoutConstraint: 0x7fbf99667eb0 V: | - ( 20 ) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido
"<NSLayoutConstraint: 0x7fbf9966c800 ''UIInputWindowController-top'' V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido )
UIRemoteKeyboardWindow:
<UIRemoteKeyboardWindow: 0x7fbf994ceb80; marco = (0 0; 320 568); opaco = NO; autoresize = W + H; layer = <UIWindowLayer: 0x7fbf994cf190>>,
("<NSLayoutConstraint: 0x7fbf994cfb20 V: | - ( 20 ) - [UIInputSetContainerView: 0x7fbf99744ec0] (Nombres: ''|'': UIRemoteKeyboardWindow: 0x7fbf994ceb80)>",
... omitido
"<NSLayoutConstraint: 0x7fbf9966c800 ''UIInputWindowController-top'' V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0] (Nombres: ''|'': UITextEffectsWindow: 0x7fbf994cc810)>",
... omitido )
Para comprender el lenguaje de formato visual, lea https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html
Parece que las restricciones de diseño vertical en el formato "Diseño vertical V: [topField] -XX- [bottomField]" cambia de ...
NSLayoutConstraint: 0x7fbf99667eb0 V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0]
a...
NSLayoutConstraint: 0x7fbf99667eb0 V: | - (20) - [UIInputSetContainerView: 0x7fbf99668ce0]
... para ambas ventanas: UITextEffectsWindow y UIRemoteKeyboardWindow; sin embargo, ...
NSLayoutConstraint: 0x7fbf9966c800 ''UIInputWindowController-top'' V: | - (0) - [UIInputSetContainerView: 0x7fbf99668ce0]
...no.
Entonces, de lo que puedo deducir, la ventana ajusta su restricción para tener en cuenta la barra de estado de llamadas entrantes, pero el UIInputWindowController no lo hace. Por lo tanto, llega el conflicto de restricción.
Pero la trama se complica ...
Después del conflicto de restricciones inicial resultante del cambio de la barra de estado de llamadas entrantes, las restricciones no cambian, y la prioridad es la misma, pero el conflicto de restricciones no surge con el cambio adicional de la barra de estado de llamadas entrantes o salientes. Pero, esto solo porque el conflicto inicial ya fue lanzado.
¡Espero que esto ayude! Salud.
Gracias a todos los colaboradores originales.