Pregunta

He implementado un UISearchBar en una vista de tabla y casi todo está funcionando, excepto una pequeña cosa: Cuando entro en texto y luego presione el botón de búsqueda en el teclado, el teclado se va, los resultados de la búsqueda son los únicos elementos que aparecen en la mesa, las estancias de texto en el UISearchBar, pero el botón cancelar se desactiva.

He estado tratando de conseguir mi lista lo más cercano a la funcionalidad de la aplicación de Apple y contactos cuando se pulsa buscar en esa aplicación, no se deshabilita el botón Cancelar.

Cuando miré en el archivo de cabecera UISearchBar, me di cuenta de una bandera para autoDisableCancelButton bajo la estructura _searchBarFlags pero es privado.

¿Hay algo que me falta cuando la configuración UISearchBar?

¿Fue útil?

Solución

I encontró una solución. Puede utilizar este ciclo for para recorrer los subvistas de la barra de búsqueda y permitir que cuando se pulsa 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;
    }
}

Otros consejos

he tenido que ajustar esto un poco para conseguir que funcione para mí 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;
            }
        }
    }
}

Hay dos vías para 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;
    }
}

Se debe ir con el segundo, no se bloqueará su aplicación si Apple va a cambiar en el fondo.

Por cierto, he comprobado a partir de iOS 4.0 a 8.2 y no hay cambios, también lo uso en mi tienda solicitud aprobada sin ningún problema.

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

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

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

IE, otras soluciones no manejar cuando el teclado se desestimó porque el usuario arrastra 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];

Ninguna de las respuestas trabajó para mí en absoluto. Estoy focalización iOS 7. Pero he encontrado 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, el aparece UISearchBar con el botón Cancelar se activa, el que muestra el teclado y la pantalla de búsquedas recientes. Desplazarse por la pantalla y búsquedas recientes que oculta el teclado, pero se mantiene el botón Cancelar activado.

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"];
}

Me llegó a esta solución mediante el establecimiento de un punto de ruptura en scrollViewWillBeginDragging: de mi vista de tabla. Miré a mi UISearchBar y mostró sus subvistas. Siempre tiene sólo uno, que es de tipo UIView (mi variable de searchBarSubview).

introducir descripción de la imagen aquí

A continuación, UIView que tiene una llamada NSArray subviewCache y me di cuenta de que el último elemento, que es la tercera, es de tipo UINavigationButton, no en la API pública. Así que me puse a su uso valor clave de codificación en su lugar. He comprobado si el UINavigationButton responde a setEnabled:, y por suerte, lo hace. Así que me puse a la propiedad @YES. Resulta que que UINavigationButton es en el botón Cancelar.

Esto se ve obligada a romper si Apple decide cambiar la implementación de las entrañas de un UISearchBar, pero qué demonios. Funciona por ahora.

Según mi respuesta aquí , colocar esto en tu 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);
    });
}

Para MonoTouch o Xamarin iOS I tienen la siguiente C # solución de trabajo para iOS 7 y el 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 David Douglas .

Una respuesta más completa:

  • desde iOS 7, hay un nivel adicional de subvistas bajo la Searchbar
  • un buen lugar para que el botón de cancelación es de 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
        }
      })
    }
  }
}

Aquí hay una solución Swift 3 que hace uso de extensiones para obtener el botón de cancelación 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
            }
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top