iphone - superior - La forma correcta de ocultar la barra de estado en iOS, con la animación y el cambio de tamaño de la vista raíz
dock transparente en ios 11 (7)
Considere un controlador de vista que necesita deslizar hacia afuera (u ocultar) la barra de estado cuando se hace clic en un botón.
- (void) buttonClick:(id)sender
{
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
}
Lo anterior oculta efectivamente la barra de estado, pero no cambia el tamaño de la vista raíz de forma adecuada, dejando un espacio de 20 píxeles en la parte superior.
Lo que esperaba era que la vista raíz se expandiera sobre el espacio que previamente usaba la barra de estado (animada, con la misma duración que la animación de la barra de estado).
¿Cuál es la forma correcta de hacer esto?
(Soy consciente de que hay muchas preguntas similares, pero no pude encontrar ninguna sobre ocultar la barra de estado bajo demanda en lugar de ocultarla para mostrar un nuevo controlador de vista)
El enfoque de la "fuerza bruta"
Obviamente, los siguientes trabajos ...
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.view.frame;
frame.origin.y -= 20;
frame.size.height += 20;
self.view.frame = frame;
}];
... pero tiene desventajas:
- Codifica la duración de la animación de diapositivas
- Códigos duros de la altura de la barra de estado
- El origen de la vista raíz permanece en (0, -20). Me gusta que mis cuadros comiencen en (0,0) siempre que sea posible.
Lo que ya probé
- Se aseguró de que la máscara de autoevaluación de la vista raíz tenga
UIViewAutoresizingFlexibleTopMargin
yUIViewAutoresizingFlexibleHeight
. - Se llama
[self.view setNeedsLayout]
después de ocultar la barra de estado. - Se llama
[self.view setNeedsDisplay]
después de ocultar la barra de estado. - Establezca
wantsFullScreenLayout
enYES
antes y después de ocultar la barra de estado.
Conozco un camino para esto pero las desventajas también son obvias. Puede establecer self.wantsFullScreenLayout = YES;
en su viewDidLoad
y configure su archivo xib tan grande como la pantalla (320x480 y 320x568 para iPhone5). Pero esto significa que el área debajo de la barra de estado tampoco es visible. Y al usar de esta manera, su vista tampoco se expandirá cuando oculte la barra de estado. Puede considerarlo de esta manera si no tiene algo que mostrar en el área de la barra de estado.
Después de pasar horas experimentando y buscando respuestas; particularmente esta respuesta . Con un poco de ajuste, lo he logrado con éxito, ¡ahora el espacio más alto, 20px, se ha ido entre la transición!
Supongamos que tenemos un BOOL isStatusBarEnabled
ivar que indicará si deberíamos tener la barra de estado oculta o no (por ejemplo, al acceder a NSUserDefault
para verificar boolValueForKey
).
Entonces, primero verificamos si si statusBar ya está oculto o no a través de [[UIApplication sharedApplication] isStatusBarHidden]
, si no está oculto (== se muestra), lo ocultamos! De lo contrario, ¡haz lo contrario!
Para corregir 20px cuando se muestra el estado, pero la navegación no está correctamente presionada, simplemente agregue 20 puntos al
origin.y
deself.navgigationController.navigationBar.frame
.Haz lo mismo cuando queremos ocultar la barra de estado, simplemente elimina esos 20 puntos de
origin.y
deself.navgigationController.navigationBar.frame
así que simplemente déjalo0
.
¡eso es todo!
@implementation SomeViewController {
BOOL isStatusBarEnabled;
}
// ...
- (void)toggleStatusBar
{
UINavigationBar *navBar = self.navigationController.navigationBar;
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to regular mode
// Show status bar
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.3
animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x, 20, navBar.frame.size.width, navBar.frame.size.height);
} completion:nil];
} else if (![[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to fullscreen mode
// Hide status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.4
animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x, 0, navBar.frame.size.width, navBar.frame.size.height);
} completion:nil];
}
}
// ...
... entonces, en mi caso, tengo una tecla de configuración para que el usuario elija alternar mostrar / ocultar la barra de estado.
// ...
- (void)onDefaultsChanged:(NSNotification*)aNotification
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
isStatusBarEnabled = [standardDefaults boolForKey:kStatusBar];
if (isStatusBarEnabled) {
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to regular mode
// Show status bar
[self toggleStatusBar];
} else {
// Change to fullscreen mode
// Hide status bar
[self toggleStatusBar];
}
// ...
}
¡Eso es!
Esto funciona bien y no tiene nada codificado .
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
self.navigationController.navigationBar.frame = self.navigationController.navigationBar.bounds;
self.view.window.frame = CGRectMake(0, 0, appFrame.size.width, appFrame.size.height);
}];
Ocultar o Mostrar barra de estado que también reajusta el tamaño de la vista:
-(void)statusBar:(BOOL)status {
UIViewController *rootViewController = self.view.window.rootViewController;
UIView *view = rootViewController.view;
// Hide/Unhide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:status]; // BOOL : YES or NO
// statusBar frame
CGRect statusBarFrame = [UIApplication.sharedApplication statusBarFrame];
// Establish baseline frame
CGRect newViewFrame = self.view.window.bounds;
// Check statusBar frame is worth dodging
if (!CGRectEqualToRect(statusBarFrame, CGRectZero)) {
UIInterfaceOrientation currentOrientation = rootViewController.interfaceOrientation;
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
// If portrait need to shrink height
newViewFrame.size.height -= statusBarFrame.size.height;
if (currentOrientation == UIInterfaceOrientationPortrait) {
// If not upside-down move down origin
newViewFrame.origin.y += statusBarFrame.size.height;
}
} else { // Is landscape
// portrait shrink width
newViewFrame.size.width -= statusBarFrame.size.width;
if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
// If the status bar is on the left side of the window move origin
newViewFrame.origin.x += statusBarFrame.size.width;
}
}
}
view.frame = newViewFrame; // pass new frame
}
método de llamada (mensaje):
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
[self statusBar:NO];
} else {
[self statusBar:YES];
}
Para aquellos que están intentando implementar esto con la apariencia de la barra de estado basada en el controlador de vista, debe implementar el método prefersStatusBarHidden en su controlador de vista
- (BOOL)prefersStatusBarHidden
{
// If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
return (self.statusBarHidden) ? YES : NO;
}
Y luego, en su método de clic de botón:
- (void) buttonClick:(id)sender
{
// Switch BOOL value
self.statusBarHidden = (self.statusBarHidden) ? NO : YES;
// Update the status bar
[UIView animateWithDuration:0.25 animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
}
Para establecer el estilo de animación, usa esto:
-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
return UIStatusBarAnimationSlide;
}
Y para personalizar el estilo:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
Para mayor comodidad, una variante Swift 4 de la respuesta de @ awfulcode:
var statusBarHidden = false {
didSet {
UIView.animate(withDuration: 0.25) {
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
return .fade
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
Puede presentar y luego cerrar el controlador de vista modal para ocultar la barra de estado correctamente
- (void)toggleStatusBar {
BOOL isStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden];
[[UIApplication sharedApplication] setStatusBarHidden:!isStatusBarHidden];
UIViewController *vc = [[UIViewController alloc] init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
[vc release];
}
Usé este código en el método "willAnimateRotationToInterfaceOrientation" para orientación horizontal y todo está funcionando correctamente. Pero no sé si funcionará con la animación.