Tengo un UISearchBar que tiene un botón de cancelar (se muestra el uso de -(void)setShowsCancelButton:animated). He cambiado la tintColor de la barra de búsqueda como este en un intento de conseguir una grisáceo barra de búsquedas:

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
searchBar.tintColor = [UIColor colorWithWhite:0.8 alpha:1.0];

Esto es lo que se ve ahora – observe cómo el botón de cancelar es también gris: http://twitpic.com/c0hte

Hay una manera de configurar el color del botón cancelar por separado lo que se parece más a esto: http://twitpic.com/c0i6q

  • ¿Por qué no simplemente incrustar imágenes aquí ?
InformationsquelleAutor Chu Yeow | 2009-07-29

19 Comentarios

  1. 13

    Lo que quieres hacer es bastante difícil. No hay ninguna integrada en el gancho para conseguir en el botón cancelar.

    Sin embargo, hay un par de opciones si usted está dispuesto a jimmy abra el capó.

    Primero, UISearchBar es un UIView, y el botón Cancelar es también una vista, que se añade en la barra de búsqueda como una subvista, tal como era de esperar.

    He experimentado un poco, y puedo decirles que cuando el botón está en la pantalla tiene un tamaño de 48,30.

    Así que en viewWillAppear, usted puede hacer algo como esto:

    1. Encontrar el botón cancelar ver en [barra de búsquedas subvistas] buscando uno con el tamaño de la 48,30. (No sólo parece ser uno — esto podría cambiar…) podría ser doblemente cuidadoso y buscar uno que está aproximadamente en la posición correcta (diferencia en el paisaje y el retrato).

    2. Agregar una subvista el botón cancelar.

    3. La subvista debe ser un UIControl (de modo que usted puede establecer enabled = NO, con el fin de asegurarse de eventos de toque de llegar a la real en el botón cancelar)

    4. Se necesita tener el color de la derecha y esquinas redondeadas; usted necesitará cambiar el tamaño de las razones que todavía no entiendo (55,30 parece funcionar)

    5. Esto funcionará si la barra de búsquedas.showsCancelButton siempre es SÍ; si usted desea que desaparezca cuando no la edición de la cadena de búsqueda, usted tendrá que encontrar un gancho para agregar la superposición cada vez que aparece el botón cancelar.

    6. Como se puede ver, esto es algo feo retoques. Hacerlo con los ojos abiertos.

    • Tenía la esperanza de que no se acercaba a algo como esto 🙂 funciona de la manera que usted describe (excepto el tamaño del botón cancelar es de alguna manera 55×30 para mí). Todavía necesita para jugar con conseguir el look de la derecha, pero probablemente funciona, otros que la fealdad de este enfoque. Muchas gracias por tu ayuda!
    • Hmm! Todos los que me gustaría hacer es cambiar el tintColor del Ámbito de aplicación de la barra de botones. Tal vez algo similar me llevaría ese punto de vista demasiado … pero es tan frágil. Yecch. Decisiones las decisiones.
    • jandrea — poner en marcha su propia pregunta y me apunte a ella — voy a intentar explicar cómo hacer algo similar.
    • Esta no es una buena idea. El ancho del botón cancelar cambiará dependiendo de los usuarios, configuración de idioma, como en «cancelar» en otros idiomas será más largo o más corto.
    • a continuación, utilice [subvista isKindOfClass:[UIButton clase]] para encontrar el botón cancelar
    • esto hizo que el trabajo.
    • Si usted está apuntando a iOS 5+, considerar las respuestas dadas por el pollo y Yiming Tang (búsqueda de estos nombres en esta página para encontrarlos).
    • Ha cambiado algo… Cuando me cambia el tono de color de la Barra de Búsqueda en IB blanco, el botón cancelar es el mismo color; blanco. Después de cancelar y volver a la búsqueda, el botón cancelar es de color azul. Su peculiar comportamiento.
    • No funciona en iOS 10.

  2. 27

    Puede utilizar UIAppearance a estilo el botón cancelar sin la iteración subvistas de la UISearchBar, pero el UIButton encabezado actualmente no tiene ningún métodos anotados con UI_APPEARANCE_SELECTOR.

    EDICIÓN: profundizar el subvistas hasta que el botón cancelar

    Pero, en general, devuelve nil hasta
    searchBar.setShowsCancelButton(true, animated: true) se llama.

    extension UISearchBar {
    
    var cancelButton : UIButton? {
        if let view = self.subviews.first {
            for subView in view.subviews {
                if let cancelButton = subView as? UIButton {
                    return cancelButton
                }
            }
        }
        return nil
    }
    }
    • [[UIButton appearanceWhenContainedIn:[MySearchBar clase], nil] setBackgroundImage:… forState:UIControlStateNormal];
    • Lo curioso es que el botón Cancelar los estados de que se trata de un UIButton en UISearchBar cabecera, pero mi UIBarButton apariencia proxies fueron anulando el estilo. Así que terminé estilo de mi botón Cancelar [[UIBarButtonItem appearanceWhenContainedIn: [UISearchBar class], [ContainingClass class], nil] setTintColor:UIColorFromRGB(0xc5c2b6)];
    • Esta es la mejor respuesta para iOS 5+. Pollo del comentario debe ser en la respuesta en sí.
    • Acaba de darse cuenta de que el uso de [[UIButton apariencia… va a editar el botón X para borrar lo que ha escrito. El uso de [[UIBarButtonItem apariencia lugar.
    • Cómo podría cambiar a UIBarButtonItem? Se debe UIButton, pero yo uso UIButton, como se dijo, va a editar en el botón X, entonces, ¿cómo se hizo esto ?
    • Soy capaz de cambiar el color de la fuente con este enfoque, pero no la imagen de fondo, aunque esto es especificada como un aspecto selector en el archivo de encabezado
    • UIBarButtonItem tiene una apariencia diferente selector para la imagen de fondo, setBackgroundImage:forState:barMetrics:
    • No funciona en iOS 10

  3. 20

    En iOS 5.0+, puede utilizar el appearnce proxy.

    Antes de que la barra de búsqueda se mostró.:

    UIBarButtonItem *searchBarButton = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
    [searchBarButton setBackgroundImage:myCancelButtonImageNormal forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    [searchBarButton setBackgroundImage:myCancelButtonImageHighlighted forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
    [searchBarButton setTitleTextAttributes:barButtonTitleTextAttributesNormal forState:UIControlStateNormal];
    [searchBarButton setTitleTextAttributes:barButtonTitleTextAttributesHighlighted forState:UIControlStateHighlighted];

    Si utiliza [UIButton appearanceWhenContainedIn:[UISearchBar class], nil], afectará a otros botones (por ejemplo, botón borrar). Así que, es mejor no utilizar UIButton‘s aspecto. Trate de UIBarButtonItem.

    • Esta es la verdadera solución al problema! Gracias!
    • Estoy a programar para iOS 5+ y esto funcionó bien para mí.
  4. 19

    Cambiar el título del botón ‘Cancelar’:

    [[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"newTitle" forState:UIControlStateNormal];

    Swift equivalente:

       let cancelButton = UIButton.appearance(whenContainedInInstancesOf: [UISearchBar.self])
       cancelButton?.setTitle("cancel".localized, for: .normal)
    • Como de iOS5, este es el método más fácil. Gracias Neru.
    • Es mi placer.
    • Superlike (y)..
    • Genial!!! Gracias..
    • No funciona para iOS 10 y XCode 8+ 🙁
  5. 17

    Pesar de que esto podría no ser exactamente pertinentes a la pregunta original, la solución es todavía aplicable en el más amplio sentido de tratar de personalizar el botón Cancelar en el UISearchBar. Pensaba que esto va a ayudar a otros que están atrapados en un escenario.

    Mi situación iba a cambiar el botón de cancelación del título, pero con una vuelta de tuerca, en el que yo no quería mostrar el botón cancelar de forma predeterminada, pero sólo quería que se muestre, cuando el usuario entra en el modo de búsqueda (haciendo clic en el campo de búsqueda de texto). En este instante, yo quería el botón cancelar para llevar la leyenda «Hecho» («Cancelar» estaba dando un significado diferente a la pantalla de mi, por lo tanto la personalización).

    Sin embargo, esto es lo que hice (una combinación de caelavel y Arenim soluciones):

    Subclases UISearchBar como MyUISearchBar con estos dos métodos:

    -(void) setCloseButtonTitle: (NSString *) title forState: (UIControlState)state
    {
        [self setTitle: title forState: state forView:self];
    }
    
    -(void) setTitle: (NSString *) title forState: (UIControlState)state forView: (UIView *)view
    {
        UIButton *cancelButton = nil;
        for(UIView *subView in view.subviews){
            if([subView isKindOfClass:UIButton.class])
            {
                cancelButton = (UIButton*)subView;
            }
            else
            {
                [self setTitle:title forState:state forView:subView];
            }
        }
    
        if (cancelButton)
            [cancelButton setTitle:title forState:state];
    
    }

    Y en el viewcontroller que utiliza esta barra de búsquedas, el siguiente trozo de código se ocupa de mostrar el botón de cancelar y personalización de su título:

    - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
    {
        MyUISearchBar *sBar = (MyUISearchBar *)searchBar;
        [sBar setShowsCancelButton:YES];
        [sBar setCloseButtonTitle:@"Done" forState:UIControlStateNormal];   
    }

    Extrañamente, no tuve que hacer nada para ocultar el botón de cancelar, ya que está oculta de manera predeterminada, cuando el modo de búsqueda se sale.

  6. 7

    Usted puede encontrar el botón cancelar recorrer las subvistas de la barra de búsqueda y comprobación para el tipo de clase (en lugar de el tamaño):

    UIButton *cancelButton = nil;
    for(UIView *subView in yourSearchBar.subviews){
        if([subView isKindOfClass:UIButton.class]){
        cancelButton = (UIButton*)subView;
        }
    }

    Y, a continuación, cambiar el tinte de color:

    [cancelButton setTintColor:[UIColor colorWithRed:145.0/255.0 green:159.0/255.0 blue:179.0/255.0 alpha:1.0]];
    • Esto le da una advertencia de que cancelButton no puede responder a setTintColor ya que este es un indocumentado de la API. Este también es probable que obtiene de su aplicación rechazada por Apple para el uso de un indocumentado de la API.
    • no te olvides de la ruptura de la instrucción if
    • subvistas contiene sólo UISearchBarBackground y UISearchBarTextField tipo de vista, no ver para UIButton tipo. Estoy usando iOS5.
  7. 7

    Si quieres configurar el botón cancelar en UISearchBar usted debe obtener la UIButton objeto de su UISearchBar objeto. Ejemplo a continuación

    UISearchBar *s_bar = [[UISearchBar alloc] initWithFrame:CGRectMake(50,20,300,30)];
    s_bar.delegate = self;
    s_bar.barStyle = UIBarStyleDefault;
    s_bar.showsCancelButton = YES;
    UIButton *cancelButton;
    for (id button in s_bar.subviews)
    {
        if ([button isKindOfClass:[UIButton class]])
        {
            cancelButton=(UIButton*)button;
            break;
        }
    }
    • Esto funciona, pero solo podrás hacerlo cuando el botón cancelar es visible.
    • para mí esto si nunca devuelve true. Im sólo UISearchBarBackground UISearchBarTextField tipo de puntos de vista aquí. Aquí está mi código. para (UIView *subvista en [searchField subvistas]) { NSLog([NSString stringWithFormat:@»%@», [subvista de la clase]); if([subvista isKindOfClass: [UIButton clase]]){ //hacer algo. }//end if }//end, pero este si nunca devuelve true. Estos NSLog imprime UISearchBarBackground y UISearchBarTextField …
  8. 4

    Personalizado UISearchBar y reemplazar el método -addSubview:

    - (void) addSubview:(UIView *)view {
        [super addSubview:view];
    
        if ([view isKindOfClass:UIButton.class]) {
            UIButton *cancelButton = (UIButton *)view;
            [cancelButton setBackgroundImage:[UIImage imageNamed:@"xxxx.png"] forState:UIControlStateNormal];
            [cancelButton setBackgroundImage:[UIImage imageNamed:@"yyyy.png"] forState:UIControlStateHighlighted];
        }
    }
    • Genio, me gusta este enfoque mucho mejor que el desordenado de la iteración.
  9. 4

    Me voy a dar una detallada respuesta con respecto a la UIAppearance técnica. En primer lugar, es necesario comprender que el botón cancelar es de un privado UINavigationButton:UIButton. Después de algunos inspección, parece que UINavigationButton responderá a aquellas UIAppearance selectores:

    //inherited from UINavigationButton
    @selector(setTintColor:)
    @selector(setBackgroundImage:forState:style:barMetrics:)
    @selector(setBackgroundImage:forState:barMetrics:)
    @selector(setTitleTextAttributes:forState:)
    @selector(setBackgroundVerticalPositionAdjustment:forBarMetrics:)
    @selector(setTitlePositionAdjustment:forBarMetrics:)
    @selector(setBackButtonBackgroundImage:forState:barMetrics:)
    @selector(setBackButtonTitlePositionAdjustment:forBarMetrics:)
    @selector(setBackButtonBackgroundVerticalPositionAdjustment:forBarMetrics:)
    
    //inherited from UIButton
    @selector(setTitle:forState:)

    Coincidentemente, los selectores de coincidir con las de un UIBarButtonItem. Significado el truco es usar dos separados UIAppearance para manejar la clase privada UINavigationButton.

    /* dual appearance technique by Cœur to customize a UINavigationButton */
    Class barClass = [UISearchBar self];
    
    UIBarButtonItem<UIAppearance> *barButtonItemAppearanceInBar = [UIBarButtonItem appearanceWhenContainedIn:barClass, nil];
    [barButtonItemAppearanceInBar setTintColor:...];
    [barButtonItemAppearanceInBar setBackgroundImage:... forState:... style:... barMetrics:...];
    [barButtonItemAppearanceInBar setBackgroundImage:... forState:... barMetrics:...];
    [barButtonItemAppearanceInBar setTitleTextAttributes:... forState:...];
    [barButtonItemAppearanceInBar setBackgroundVerticalPositionAdjustment:... forBarMetrics:...];
    [barButtonItemAppearanceInBar setTitlePositionAdjustment:... forBarMetrics:...];
    //only for a backButton in an UINavigationBar, not for a cancelButton in an UISearchBar
    //[barButtonItemAppearanceInBar setBackButtonBackgroundImage:... forState:... barMetrics:...];
    //[barButtonItemAppearanceInBar setBackButtonTitlePositionAdjustment:... forBarMetrics:...];
    //[barButtonItemAppearanceInBar setBackButtonBackgroundVerticalPositionAdjustment:... forBarMetrics:...];
    
    UIButton<UIAppearance> *buttonAppearanceInBar = [UIButton appearanceWhenContainedIn:barClass, nil];
    //warning: doesn't work for iOS7+
    [buttonAppearanceInBar setTitle:... forState:...];

    Esto te permitirá personalizar tu botón Cancelar tanto como usted desea.

    • para cambiar el título en iOS7+, usted debe utilizar el proceso de localización de la aplicación (tener una carpeta de.lproj, fr.lproj, …)
  10. 1

    Después de haber inicializado su UISearchBar, usted puede probar en su subvistas y personalizar cada uno de ellos. Ejemplo:

    for (UIView *view in searchBar.subviews) {
    
        //if subview is the button
        if ([[view.class description] isEqualToString:@"UINavigationButton"]) {
    
            //change the button images and text for different states
            [((UIButton *)view) setEnabled:YES];
            [((UIButton *)view) setTitle:nil forState:UIControlStateNormal];
            [((UIButton *)view) setImage:[UIImage imageNamed:@"button image"] forState:UIControlStateNormal];
            [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button"] forState:UIControlStateNormal];
            [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button_pressed"] forState:UIControlStateSelected];
            [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button_pressed"] forState:UIControlStateHighlighted];
    
        //if the subview is the background
        }else if([[view.class description] isEqualToString:@"UISearchBarBackground"]) {
    
            //put a custom gradient overtop the background
            CAGradientLayer *gradient = [CAGradientLayer layer];
            gradient.frame = view.bounds;
            gradient.colors = [NSArray arrayWithObjects:(id)[[some uicolor] CGColor], (id)[[another uicolor] CGColor], nil];
            [view.layer insertSublayer:gradient atIndex:0];
    
        //if the subview is the textfield
        }else if([[view.class description] isEqualToString:@"UISearchBarTextField"]){
    
            //change the text field if you wish
    
        }
    
    }

    Funcionado muy bien para mí! Especialmente el gradiente 🙂

  11. 1

    Swift 2.1.1:

    Hay no hay manera fácil de enganchar y estilo de la barra de búsqueda, usted necesita para agarrar la subvista manualmente desde la barra de búsqueda y, a continuación, aplicar los cambios.

    var cancelButton: UIButton
    let topView: UIView = self.customSearchController.customSearchBar.subviews[0] as UIView
    for subView in topView.subviews {
     if subView.isKindOfClass(NSClassFromString("UINavigationButton")!) {
        cancelButton = subView as! UIButton
        cancelButton.enabled = true
        cancelButton.setTitle("TestTitle", forState: UIControlState.Normal) //Change to set the title
        cancelButton.setBackgroundImage(UIImage(named: "ImageName"), forState: .Normal) //Change this to set a custom cancel button image, set the title to "" to remove 'Cancel' text
       }
    }
  12. 1

    Primero de todo me gustaría agradecer a @Eliott de este https://stackoverflow.com/a/37381821/1473144

    Tuve que hacer algunos ajustes para su respuesta a trabajar en mi especificaciones que van a continuación.
    Por favor, pido a la OP a actualizar la aceptada respuesta ya que es MUY anticuado.

    Swift 3, iOS 10 & Xcode 8.2.1

    searchBar.showsCancelButton = true
    var cancelButton: UIButton
    let topView: UIView = self.searchBar.subviews[0] as UIView
    for subView in topView.subviews {
        if let pvtClass = NSClassFromString("UINavigationButton") {
            if subView.isKind(of: pvtClass) {
                cancelButton = subView as! UIButton
    
                cancelButton.setTitle("", for: .normal)
                cancelButton.tintColor = UIColor.black
                cancelButton.setImage(#imageLiteral(resourceName: "searchX"), for: .normal)
            }
        }
    
    }
  13. 0

    Bien, aquí es la función, que puede cambiar Cancelar la etiqueta del botón. Modificar, si quieren.
    El uso es:

    nStaticReplaceStringInView(mySearchBar, @"Cancel", @"NewCancelButtonLabel");
    
    void nStaticReplaceStringInView(UIView * view, NSString * haystack, NSString * needle)
    {
     for(int i=0; i<[view.subviews count]; i++)
     {
      nStaticReplaceStringInView([view.subviews objectAtIndex:i], haystack,needle);
     }
     if([view respondsToSelector:@selector(titleForState:)])
     {
      //NSLog(@"%@ || %@",[view titleForState:UIControlStateNormal], haystack);
      if(NSStrEq([view titleForState:UIControlStateNormal] , haystack))
      {
       [view setTitle: needle forState: UIControlStateNormal];
      }
     }
    }
  14. 0
    - (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar 
    {        
        NSArray *arr = [theSearchBar subviews];
        UIButton *cancelButton = [arr objectAtIndex:3];
        [cancelButton setTitle:@"yourtitle" forState:UIControlStateNormal];    
    }

    Acaba de tomar un registro de arr amd ver en el índice de control de mentiras. De la misma manera que u puede establecer UITextField propiedades:

        NSArray *arr = [searchbar subviews];
        UITextField *searchfield = [arr objectAtIndex:2];
        [searchfield setTextAlignment:UITextAlignmentRight];
  15. 0

    Tengo muchos UISearchBar elementos a lo largo de mi aplicación, así que escribí esta categoría para agregar una propiedad para que pueda acceder a mySearchBar.cancelButton. (Si eres nuevo en categorías, leer más acerca de la extensión de los objetos con las Categorías aquí.)

    Tenga en cuenta que usted debe acceder a éste cuando el botón Cancelar es visible porque UISearchBar parece crear un nuevo objeto de botón cada vez que se muestra. No guardar el puntero a la cancelButton, acaba de obtener de él cuando sea necesario:

    @interface UISearchBar (cancelButton)
    
    @property (readonly) UIButton* cancelButton;
    
    - (UIButton *) cancelButton;
    
    @end
    
    @implementation UISearchBar (cancelButton)
    
    - (UIButton *) cancelButton {
        for (UIView *subView in self.subviews) {
            //Find the button
            if([subView isKindOfClass:[UIButton class]])
            {
                return (UIButton *)subView;
            }
        }
    
        NSLog(@"Error: no cancel button found on %@", self);
    
        return nil;
    }
    
    @end
  16. 0

    manera estúpida de

    for(id cc in [SearchBar subviews])
    {
        if([cc isKindOfClass:[UIButton class]])
        {
            UIButton *btn = (UIButton *)cc;
            ......
            Do whatever you want
            .......        
        }
    }
  17. 0
    extension UISearchBar {
    var cancelButton : UIButton? {
        let topView: UIView = self.subviews[0] as UIView
    
        if let pvtClass = NSClassFromString("UINavigationButton") {
            for v in topView.subviews {
                if v.isKind(of: pvtClass) {
                    return v as? UIButton
                }
            }
        }
    
        return nil
    }
    }
  18. 0
    UISearchBar *searchBar;
    [searchBar setShowsCancelButton:YES animated:YES];
    
    UIButton *cancelButton = 
    YES == [searchBar respondsToSelector:NSSelectorFromString(@"cancelButton")] ? 
    [searchBar valueForKeyPath:@"_cancelButton"] : nil;
    
    cancelButton.titleEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 10);
    [cancelButton setTitle:@"New :)" forState:UIControlStateNormal];
  19. 0

    Para iOS 11 y Swift 4.
    Crear una subclase de UISearchController.
    Método de reemplazo:

    override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            print("layout")
            if let btn = searchBar.subviews[0].subviews[2] as? UIButton {
                btn.frame = CGRect(x: 306, y: 20, width: 53, height: 30)
            }
    }

Dejar respuesta

Please enter your comment!
Please enter your name here