Evita que UISearchDisplayController oculte una UINavigationBar

Beware: This post was published 7 years ago and its content may be outdated.


UISearchDisplayControllerWithoutAnimation: Subclase de UISearchDisplayController

El funcionamiento estándar de UISearchDisplayController es ocultar la barra de navegación (UINavigationBar) cuando se inicia una búsqueda. Este comportamiento nos puede parecer adecuado, pero en ciertas ocasiones puede que no queramos que se superponga y queramos tener visible la barra de navegación (UINavigationBar).

Actualmente cuando se activa la barra de búsqueda se ejecuta el método privado setActive:animated:. La única manera de evitar que se oculte la barra de navegación es crear una subclase de UISearchDisplayController y reemplazar dicho método por el siguiente, que anima la barra de búsqueda sin ocultar la barra de navegación (realmente oculta primero la barra de navegación y luego la muestra, de modo que a efectos prácticos parece que siempre está ahí):

- (void)setActive:(BOOL)visible animated:(BOOL)animated;
{
    if (self.active == visible) return;
    [self.searchContentsController.navigationController setNavigationBarHidden:YES animated:NO];
    [super setActive:visible animated:animated];
    [self.searchContentsController.navigationController setNavigationBarHidden:NO animated:NO];
    if (visible)
	{
        [self.searchBar becomeFirstResponder];
    }
	else
	{
        [self.searchBar resignFirstResponder];
    }
}

La nueva clase puede llamarse, por ejemplo, UISearchDisplayControllerWithoutAnimation (aunque realmente sí que tiene animación). Su interfaz será algo así (recordad que lo heredamos todo de UISearchDisplayController así que no necesitamos declarar ningún método más ni ninguna propiedad, tan sólo reemplazar el método setActive:animated:, que haremos en la implementación):

#import <UIKit/UIKit.h>
@interface UISearchDisplayControllerWithoutAnimation : UISearchDisplayController
{
}
@end

Y la implementación:

#import "UISearchDisplayControllerWithoutAnimation.h"
@implementation UISearchDisplayControllerWithoutAnimation
- (void)setActive:(BOOL)visible animated:(BOOL)animated;
{
 if (self.active == visible) return;
 [self.searchContentsController.navigationController setNavigationBarHidden:YES animated:NO];
 [super setActive:visible animated:animated];
 [self.searchContentsController.navigationController setNavigationBarHidden:NO animated:NO];
 if (visible)
 {
 [self.searchBar becomeFirstResponder];
 }
 else
 {
 [self.searchBar resignFirstResponder];
 }
}
@end
Añadiendo un UISearchDisplayController en Interface Builder

Añadiendo un UISearchDisplayController en Interface Builder

Cambiando la clase del UISearchDisplayController

Cambiando la clase del UISearchDisplayController

Ahora sólo queda usar UISearchDisplayControllerWithoutAnimation en lugar de UISearchDisplayController. Si hemos añadido la barra de búsqueda directamente desde Xcode, sin usar Interface Builder, no hay ningún problema, y si hemos usado Interface Builder basta con cambiar la clase del UISearchDisplayController a UISearchDisplayControllerWithoutAnimation. Si queremos añadir una nueva barra de búsqueda que no oculte la barra de navegación basta con añadir desde la librería un UISearchDisplayController, como de costumbre, y una vez añadido cambiarle la clase a UISearchDisplayControllerWithoutAnimation.

La única pega de este sistema es que tal vez en alguna nueva versión de iOS cambien el método privado setActive:animated:, con lo cual habría que revisar este nuevo método y actualizar nuestra clase personalizada. De todas maneras, parece algo poco probable, al menos en un futuro inmediato. Este método nuevo funciona sin problemas en iOS 4 y iOS 4.1, aunque seguramente funcione también en versiones anteriores (yo sólo he probado estas dos).