ios4 uisearchbar cancel-button

ios4 - UISearchBar deshabilita la desactivación automática del botón cancelar



cancel-button (10)

Aquí está mi solución, que funciona para todas las situaciones en todas las versiones de iOS.

IE, otras soluciones no se manejan cuando el teclado se descarta porque el usuario arrastró una vista de desplazamiento.

- (void)enableCancelButton:(UIView *)view { if ([view isKindOfClass:[UIButton class]]) { [(UIButton *)view setEnabled:YES]; } else { for (UIView *subview in view.subviews) { [self enableCancelButton:subview]; } } } // This will handle whenever the text field is resigned non-programatically // (IE, because it''s set to resign when the scroll view is dragged in your storyboard.) - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { [self performSelector:@selector(enableCancelButton:) withObject:searchBar afterDelay:0.001]; } // Also follow up every [searchBar resignFirstResponder]; // with [self enableCancelButton:searchBar];

Implementé UISearchBar en una vista de tabla y casi todo funciona, excepto una pequeña cosa: cuando ingreso texto y luego presiono el botón de búsqueda en el teclado, el teclado desaparece, los resultados de búsqueda son los únicos elementos que se muestran en la tabla, el texto permanece en UISearchBar, pero el botón Cancelar se desactiva.

He intentado que mi lista esté lo más cerca posible de la funcionalidad de la aplicación de contactos de Apple y cuando presionas buscar en esa aplicación, no se desactiva el botón de cancelar.

Cuando miré en el archivo de encabezado UISearchBar, noté un indicador para autoDisableCancelButton en la estructura _searchBarFlags pero es privado.

¿Hay algo que me falta cuando configuro UISearchBar?


Aquí hay una solución Swift 3 que hace uso de extensiones para obtener el botón Cancelar fácilmente:

extension UISearchBar { var cancelButton: UIButton? { for subView1 in subviews { for subView2 in subView1.subviews { if let cancelButton = subView2 as? UIButton { return cancelButton } } } return nil } }

Ahora para el uso:

class MyTableViewController : UITableViewController, UISearchBarDelegate { var searchBar = UISearchBar() func viewDidLoad() { super.viewDidLoad() searchBar.delegate = self tableView.tableHeaderView = searchBar } func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { DispatchQueue.main.async { if let cancelButton = searchBar.cancelButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true } } } }


Encontré una solución. Puede usar este for-loop para recorrer las subvistas de la barra de búsqueda y habilitarlo cuando se presiona el botón de búsqueda en el teclado.

for (UIView *possibleButton in searchBar.subviews) { if ([possibleButton isKindOfClass:[UIButton class]]) { UIButton *cancelButton = (UIButton*)possibleButton; cancelButton.enabled = YES; break; } }


Esto es lo que hizo que funcione en iOS 6 para mí:

searchBar.showsCancelButton = YES; searchBar.showsScopeBar = YES; [searchBar sizeToFit]; [searchBar setShowsCancelButton:YES animated:YES];


Hay dos formas de lograr esto fácilmente

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ // The small and dirty [(UIButton*)[searchBar valueForKey:@"_cancelButton"] setEnabled:YES]; // The long and safe UIButton *cancelButton = [searchBar valueForKey:@"_cancelButton"]; if ([cancelButton respondsToSelector:@selector(setEnabled:)]) { cancelButton.enabled = YES; } }

Deberías ir con el segundo, no bloqueará tu aplicación si Apple lo cambia en segundo plano.

Por cierto lo probé desde iOS 4.0 a 8.2 y sin cambios, también lo uso en mi aplicación aprobada por la Tienda sin ningún problema.


Ninguna de las respuestas funcionó para mí en absoluto. Me estoy orientando a iOS 7. Pero encontré una respuesta.

Lo que intento es algo así como la aplicación de Twitter para iOS. Si hace clic en la lupa en la pestaña Líneas de tiempo, aparece UISearchBar con el botón Cancelar activado, el teclado que se muestra y la pantalla de búsquedas recientes. Desplácese por la pantalla de búsquedas recientes y oculta el teclado, pero mantiene activado el botón Cancelar.

Este es mi código de trabajo:

UIView *searchBarSubview = self.searchBar.subviews[0]; NSArray *subviewCache = [searchBarSubview valueForKeyPath:@"subviewCache"]; if ([subviewCache[2] respondsToSelector:@selector(setEnabled:)]) { [subviewCache[2] setValue:@YES forKeyPath:@"enabled"]; }

Llegué a esta solución estableciendo un punto de interrupción en scrollViewWillBeginDragging: mi vista de scrollViewWillBeginDragging: Busqué en mi UISearchBar y desnudé sus subvistas. Siempre tiene solo uno, que es del tipo UIView (mi variable searchBarSubview ).

Luego, ese UIView contiene un NSArray llamado subviewCache y noté que el último elemento, que es el tercero, es del tipo UINavigationButton , no en la API pública. Así que me propuse usar codificación de clave-valor en su lugar. Comprobé si el UINavigationButton responde a setEnabled: y, por suerte, lo hace. Así que configuré la propiedad a @YES . Resulta que ese UINavigationButton es el botón Cancelar.

Esto está destinado a romperse si Apple decide cambiar la implementación de las entrañas de UISearchBar , pero qué demonios. Funciona por ahora.


Para Monotouch o Xamarin iOS, tengo la siguiente solución C # que funciona para iOS 7 e iOS 8:

foreach(UIView view in searchBar.Subviews) { foreach(var subview in view.Subviews) { //Console.WriteLine(subview.GetType()); if(subview.GetType() == typeof(UIButton)) { if(subview.RespondsToSelector(new Selector("setEnabled:"))) { UIButton cancelButton = (UIButton)subview; cancelButton.Enabled = true; Console.WriteLine("enabledCancelButton"); return; } } } }

Esta respuesta se basa en la solución de David Douglas .


Según mi respuesta aquí , coloque esto en su delegado searchBar:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { dispatch_async(dispatch_get_main_queue(), ^{ __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *); void (^ensureCancelButtonRemainsEnabled)(UIView *); weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) { for (UIView *subview in view.subviews) { if ([subview isKindOfClass:[UIControl class]]) { [(UIControl *)subview setEnabled:YES]; } weakEnsureCancelButtonRemainsEnabled(subview); } }; ensureCancelButtonRemainsEnabled(searchBar); }); }


Tuve que modificar esto un poco para que funcione en iOS7

- (void)enableCancelButton:(UISearchBar *)searchBar { for (UIView *view in searchBar.subviews) { for (id subview in view.subviews) { if ( [subview isKindOfClass:[UIButton class]] ) { [subview setEnabled:YES]; NSLog(@"enableCancelButton"); return; } } } }


Una respuesta más completa:

  • desde iOS 7, hay un nivel adicional de subvistas bajo searchBar
  • un buen lugar para habilitar el botón cancelar está en searchBarTextDidEndEditing

.

extension MyController: UISearchBarDelegate { public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { DispatchQueue.main.async { // you need that since the disabling will // happen after searchBarTextDidEndEditing is called searchBar.subviews.forEach({ view in view.subviews.forEach({ subview in // ios 7+ if let cancelButton = subview as? UIButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true return } }) // ios 7- if let cancelButton = subview as? UIButton { cancelButton.isEnabled = true cancelButton.isUserInteractionEnabled = true return } }) } } }