tutorial searchcontroller example bar ios cocoa-touch uisearchbar uisearchdisplaycontroller

example - uisearchcontroller ios



UISearchDisplayController-cómo precargar searchResultTableView (8)

Quiero mostrar algo de contenido predeterminado cuando el usuario toca la barra de búsqueda, pero antes de ingresar cualquier texto.

Tengo una solución trabajando usando settext:

- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { [searchDisplayController.searchBar setText:@" "]; }

Esto funciona pero no es elegante y el texto de sugerencia en la barra de búsqueda desaparece.

¿Existe una forma mejor de precargar los datos a SearchResultTableView en un UISearchDisplayController, sin tener que implementar toda la funcionalidad de UISearch en un controlador personalizado?

Para ver una demostración del efecto deseado, mira el cuadro de búsqueda de Safari. Si lo tocas, la interfaz de búsqueda se abrirá y se mostrarán las búsquedas anteriores.


¿Por qué no echas un vistazo al proyecto TableSearch que viene en Xcode? Más o menos aborda lo que necesitas. Muestra una tabla al principio y la sombrea cuando se toca el campo de búsqueda. Verifique TableSearch en la documentación y la referencia de la API en Xcode 4 con ayuda.

También eche un vistazo a this Casi hace lo que necesita con una UISearchBar y una UITableView. Prefiero ese enfoque en su lugar. Pellizcarlo

Y para abordar sus necesidades aún más, sugeriría usar dos fuentes de datos. Una que contenga todos los contenidos (esto es lo que mostraría al principio) y otra que contiene los resultados de búsqueda filtrados. Ahora siga adelante y vacíe la primera fuente de datos y rellénela con el contenido de la segunda para almacenar y mostrar los resultados de la búsqueda anterior. Proceda de esta manera. Utilice este enfoque en el código de TableSearch para su tarea.


Aquí hay una manera de rellenar previamente el control de búsqueda.

// 1. Guardar los resultados de la búsqueda anterior tan pronto como el usuario ingrese el texto

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { // save searchString return YES; }

// 2. cargar la cadena de búsqueda anterior en el inicio

- (void)viewDidLoad { // create data source for table view // searchData may be a NSMutableArray property defined in your interface self.searchData = // search your master list for searchString // or create your own list using any search criteria you want // or you may act depending on user preference if(!showPreviousSearch) { // [searchData removeAllObjects]; } }

// 3. proporcionar la fuente de datos correcta cuando se le solicite

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { ... } NSMutableArray *dataSource = nil; if (tableView == [[self searchDisplayController] searchResultsTableView]) { dataSource = self.searchData; } else { dataSource = self.masterData; } ... return cell; }

// Espero que esto ayude.

Gracias


Encontré una solución mucho mejor para este problema, y ​​parece funcionar perfectamente en iOS 6 y 7. Aunque todavía es un hack, es un hack mucho más limpio y seguro que el anterior. Las otras soluciones no funcionan de manera consistente y evitan que algunos métodos UISearchDisplayDelegate se activen nunca. Además, tuve problemas de inserción complejos que no pude resolver con los métodos anteriores. El principal problema con las otras soluciones es que confunden seriamente los elementos internos del UISearchDisplayController. Mi solución se basa en la observación de que UISearchDisplayContoller es un UISearchbarDelegate y que la función de atenuación y visualización automática de resultados puede activarse simulando una pulsación de tecla en el campo de búsqueda. Asi que:

- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { if ([controller respondsToSelector: @selector(searchBar:textDidChange:)]) [(id<UISearchBarDelegate>)controller searchBar: controller.searchBar textDidChange: @" "]; }

Este código es una prueba de futuro contra el bloqueo al verificar que responde al método UISearchbarDelegate y envía un espacio "" para engañar al UISearchDisplayController para que piense que el usuario ha escrito una letra.

Ahora, si el usuario escribe algo y luego lo borra, la tabla se atenuará nuevamente. Las otras soluciones intentan solucionar esto haciendo algo en el método searchDisplayController: didHideSearchResultsTableView:. Pero esto no tiene sentido para mí, ya que cuando cancele la búsqueda, tendrá que ocultar realmente la tabla de resultados y es posible que deba ejecutar el código en este caso. Mi solución para esta parte es crear una subclase (tenga en cuenta que probablemente podría usar una Categoría de Método Swizzled para que funcione en todas partes si es necesario en su proyecto):

// privately declare protocol to suppress compiler warning @interface UISearchDisplayController (Super) <UISearchBarDelegate> @end // subclass to change behavior @interface GMSearchDisplayController : UISearchDisplayController @end @implementation GMSearchDisplayController - (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchString { if (searchString.length == 0) searchString = @" "; if ([super respondsToSelector: @selector(searchBar:textDidChange:)]) [super searchBar: searchBar textDidChange: searchString]; } @end

Este código funciona interceptando el método de delegado textDidChange y cambiando cadenas nulas o vacías en la cadena de espacio @ "" evitando la ocultación / atenuación normal que se produce en una barra de búsqueda vacía. Si está utilizando este segundo bit de código, puede modificar el primer bit para pasar un nulo en lugar de @ "", ya que este segundo bit hará la conversión necesaria a @ "" por usted.

En mi propio proyecto, necesitaba manejar el caso en el que el usuario escribe un espacio, así que en lugar de @ "" arriba, usé un token definido:

// arbitrary token used internally #define SEARCH_PRELOAD_CONDITIONAL @"_#preresults#_"

Y luego manejarlo internamente convirtiéndolo de nuevo en una cadena nula:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL]) searchString = nil; }

¡Disfrutar! :)


Esto funciona en iOS 8:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView { self.searchDisplayController.searchResultsTableView.hidden = NO; } - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { self.searchDisplayController.searchResultsTableView.hidden = NO; [self.searchDisplayController.searchResultsTableView.superview.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView.superview]; CGRect frame = self.searchDisplayController.searchResultsTableView.frame; self.searchDisplayController.searchResultsTableView.frame = CGRectMake(frame.origin.x, 64, frame.size.width, frame.size.height); }

Sin embargo, no me gustó este truco y reemplacé searchDisplayController por mi propia implementación (UISearchBar con UITableView).


Ok lo tengo Precargue su fuente de datos con algunos datos y haga el siguiente pirateo (nada ilegal) y obtendrá la vista de tabla para aparecer. Tenga en cuenta que puede haber algo de limpieza que hacer, pero esto hará que se muestren sus datos predeterminados.

En viewDidLoad del controlador de vista que posee el UISearchBar:

[super viewDidLoad]; [self.searchDisplayController.searchResultsTableView reloadData]; // whatever you named your search bar - mine is property named searchBar CGRect testFrame = CGRectMake(0, 20, self.searchBar.frame.size.width, 100); self.searchDisplayController.searchResultsTableView.frame = testFrame; [self.searchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

Esto es lo que está pasando:
UISearchBar no quiere mostrar searchResultsTableView hasta que empiece a editar. Si toca el tableView (por ejemplo, reloadData), se cargará y estará allí, sentado en la memoria con frame = CGRectZero. Le da un marco adecuado y luego lo agrega a la vista de supervisión de searchBar, et voila.

Verifiqué que esto es correcto al mostrar la vista de supervisión de la barra de búsqueda y la vista de supervisión de la tablaVista después de una carga adecuada de la vista de tabla: tienen la misma vista de supervisión. Por lo tanto, vuelvo y agrego la vista de tabla a la vista previa temprano, y con toda seguridad se muestra. Para mí, se mostró atenuado (tal vez otra vista arriba? ¿Conjunto alfa más bajo?), Pero aún se podía hacer clic. No fui más lejos, pero eso definitivamente te muestra tu tableView sin la interacción del usuario.

Disfrutar,

Damien


Probé lo siguiente en iOS 9 con UISearchController.

De forma predeterminada, siempre que no haya texto en la barra UISearchBar, la tabla que se muestra será su vista de tabla original (a la que se hace referencia como originalTableView de aquí en adelante). Esto puede o no tener una capa dimsBackgroundDuringPresentation negra que depende del valor de dimsBackgroundDuringPresentation .

Una vez que el usuario ingrese cualquier texto en UISearchBar, se mostrará el contenido de la nueva vista de tabla (me referiré a esto como searchTableView ).

Tenga en cuenta que en ambas soluciones, estoy implementando UISearchController de una manera similar a como lo hace Apple en este ejemplo ; a saber, hay dos UITableViewController independientes encargados de mostrar los datos.

Solución 1: Implementación complicada, animación más suave

Para una animación más suave:

  1. Implementar los métodos willPresentSearchController y willDismissSearchController de UISearchControllerDelegate.
  2. En willPresent, actualice los datos de su tabla original para prepararse para mostrar los datos de texto que desee, luego llame a reloadData() .
  3. En willDismiss, revertir el proceso para mostrar el contenido original y llamar a reloadData() .

Ejemplo:

// here tableView refers to originalTableView extension ViewController: UISearchControllerDelegate { func willPresentSearchController(searchController: UISearchController) { data = ["A", "B", "C"] tableView.reloadData() } func willDismissSearchController(searchController: UISearchController) { data = ["a", "b", "c"] tableView.reloadData() } }

En este ejemplo ficticio, los datos se muestran como a,b,c cuando el usuario no está enfocado en la barra UISearch, pero se muestra como A,B,C una vez que el usuario toca la barra UISearch.

Solución 2: Implementación rápida, animación entrecortada

En lugar de implementar la lógica para el controlador de búsqueda tanto en originalTableView como en searchTableView, puede usar esta solución para mostrar simplemente searchTableView aunque esté oculta de forma predeterminada.

Lo más probable es que ya esté implementando el protocolo UISearchResultsUpdating. Simplemente llamando a tableView.hidden = false en ese método, debería obtener el comportamiento que tableView.hidden = false ; aunque con una animación menos que estelar.

// here tableView refers to searchTableView extension SearchViewController: UISearchResultsUpdating { func updateSearchResultsForSearchController(searchController: UISearchController) { tableView.hidden = false filterData(text: searchController.searchBar.text!) tableView.reloadData() } }


Solución de trabajo para iOS 7:

// When the tableView is hidden, put it back - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { [self.searchDisplayController.searchResultsTableView reloadData]; controller.searchResultsTableView.hidden = NO; // Also, remove the dark overlay for (UIView *v in [[controller.searchResultsTableView superview] subviews]) { // This is somewhat hacky.. if (v.alpha < 1) { [v setHidden:YES]; } } } -(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView { [self.searchDisplayController.searchResultsTableView reloadData]; if (self.searchDisplayController.active == YES) { tableView.hidden = NO; } }


Tengo la solución. Inserte estos tres métodos. Debe tener la vista de tabla precargada con los datos para que esto funcione. Tengo estos códigos trabajando en mi código, por lo que tiene que funcionar para usted siempre y cuando ya haya cargado previamente los datos y esté utilizando el controlador de pantalla de búsqueda.

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller { CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height); self.searchDisplayController.searchResultsTableView.frame = testFrame; [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView]; // [self.view addSubview:self.searchDisplayController.searchResultsTableView]; controller.searchResultsTableView.hidden = NO; } -(void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView { CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height); self.searchDisplayController.searchResultsTableView.frame = testFrame; [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView]; // [self.view addSubview:self.searchDisplayController.searchResultsTableView]; controller.searchResultsTableView.hidden = NO; } -(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller { controller.searchResultsTableView.hidden = YES; }