Crear un botón de flecha izquierda (como el estilo “Atrás” de UINavigationBar) en una UIToolbar

Me encantaría crear un botón “atrás” de flecha izquierda en el bisel en una UIToolbar .

Por lo que puedo decir, la única forma de obtener uno de estos es dejar UINavigationController en la configuración predeterminada y usa uno para el elemento de la barra izquierda. Pero no hay forma de que pueda encontrarlo para crear uno como un UIBarButtonItem , así que no puedo hacer uno en una UIToolbar estándar, a pesar de que son muy similares a UINavigationBar .

Pude crearlo manualmente con imágenes de botón, pero no puedo encontrar las imágenes de origen en ningún lado. Tienen bordes de canal alfa, por lo que la captura de pantalla y el corte no obtendrán resultados muy versátiles.

¿Alguna idea más allá de la captura de pantalla para cada tamaño y combinación de colores que pretendo utilizar?

Actualización: POR FAVOR DEJE de esquivar la pregunta y sugerir que no debería estar preguntándolo y debería estar usando UINavigationBar . Mi aplicación es Instapaper Pro. Muestra solo una barra de herramientas inferior (para ahorrar espacio y maximizar el área de contenido legible), y deseo poner un botón Atrás con forma de flecha izquierda en la parte inferior.

Decirme que no debería necesitar hacer esto no es una respuesta y ciertamente no merece una recompensa.

Utilicé la siguiente psd que obtuve de http://www.teehanlax.com/blog/?p=447

http://www.chrisandtennille.com/pictures/backbutton.psd

Luego creé una UIView personalizada que uso en la propiedad customView del elemento de la barra de herramientas.

Funciona bien para mi


Editar: Como señaló PrairieHippo , maralbjo descubrió que con el siguiente código simple, el truco (requiere una imagen personalizada en el paquete) debe combinarse con esta respuesta. Entonces aquí hay un código adicional:

 // Creates a back button instead of default behaviour (displaying title of previous screen) UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_arrow.png"] style:UIBarButtonItemStyleBordered target:self action:@selector(backAction)]; tipsDetailViewController.navigationItem.leftBarButtonItem = backButton; [backButton release]; 

El método Unicode

Creo que es mucho más fácil usar un carácter Unicode para hacer el trabajo. Puede ver las flechas buscando en Google Triangularjs Unicode o Flechas Unicode . Comenzando con iOS6, Apple cambió el personaje para que fuera un personaje emoji con un borde. Para desactivar el borde, agrego el Selector de Variación Unicode 0xFE0E.

 NSString *backArrowString = @"\U000025C0\U0000FE0E"; //BLACK LEFT-POINTING TRIANGLE PLUS VARIATION SELECTOR UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:nil action:nil]; self.navigationItem.leftButtonItem = backBarButtonItem; 

El bloque de código es solo para la demostración. Funcionaría en cualquier botón que acepte un NSString.

Para obtener una lista completa de personajes, busque en Google el carácter Unicode y lo que desee. Aquí está la entrada para Black Left-Pointing Triangle .

Resultado

El resultado

ADVERTENCIA: hay informes de que esto no funcionará en iOS 6. Esto podría funcionar solo en versiones anteriores del sistema operativo. Evidentemente, al menos un desarrollador ha rechazado su aplicación por usar este truco (ver los comentarios). Úselo bajo su propio riesgo. Usar una imagen (ver respuesta arriba) podría ser una solución más segura.

Esto se puede hacer sin agregar sus propios archivos de imagen utilizando el botón sekr1t tipo 101 para obtener la forma correcta. Para mí, el truco fue descubrir que podía usar initWithCustomView para crear BarButtonItem . Personalmente, necesitaba esto para una barra de navegación dinámica en lugar de una toolbar , pero la probé con una barra de herramientas y el código es casi el mismo:

 // create button UIButton* backButton = [UIButton buttonWithType:101]; // left-pointing shape! [backButton addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; [backButton setTitle:@"Back" forState:UIControlStateNormal]; // create button item -- possible because UIButton subclasses UIView! UIBarButtonItem* backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; // add to toolbar, or to a navbar (you should only have one of these!) [toolbar setItems:[NSArray arrayWithObject:backItem]]; navItem.leftBarButtonItem = backItem; 

Si estás haciendo esto en una barra de herramientas, tendrás que modificar cómo configuras los elementos, pero eso depende del rest de tu código y lo dejo como ejercicio para el lector. : P Esta muestra funcionó para mí (comstackda y ejecutada).

Bla, bla, lee el HIG, no uses funciones no documentadas, y todo eso. Solo hay seis tipos de botones compatibles y este no es uno de ellos.

enter image description here

En primer lugar, debe encontrar una imagen del botón Atrás. Usé una buena aplicación llamada Extractor que extrae todos los gráficos del iPhone. En iOS7 logré recuperar la imagen llamada UINavigationBarBackIndicatorDefault y estaba en color negro, ya que necesitaba un tinte rojo. Cambié el color a rojo usando Gimp.

EDITAR:

Como fue mencionado por btate en su comentario, no hay necesidad de cambiar el color con el editor de imágenes. El siguiente código debería hacer el truco:

 imageView.tint = [UIColor redColor]; imageView.image = [[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 

Luego creé una vista que contiene un imageView con esa flecha, una etiqueta con el texto personalizado y en la parte superior de la vista tengo un botón con una acción. Luego agregué una animación simple (desvanecimiento y traducción).

El siguiente código simula el comportamiento del botón Atrás, incluida la animación.

 -(void)viewWillAppear:(BOOL)animated{ UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"]]; [imageView setTintColor:[UIColor redColor]]; UILabel *label=[[UILabel alloc] init]; [label setTextColor:[UIColor redColor]]; [label setText:@"Blog"]; [label sizeToFit]; int space=6; label.frame=CGRectMake(imageView.frame.origin.x+imageView.frame.size.width+space, label.frame.origin.y, label.frame.size.width, label.frame.size.height); UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, label.frame.size.width+imageView.frame.size.width+space, imageView.frame.size.height)]; view.bounds=CGRectMake(view.bounds.origin.x+8, view.bounds.origin.y-1, view.bounds.size.width, view.bounds.size.height); [view addSubview:imageView]; [view addSubview:label]; UIButton *button=[[UIButton alloc] initWithFrame:view.frame]; [button addTarget:self action:@selector(handleBack:) forControlEvents:UIControlEventTouchUpInside]; [view addSubview:button]; [UIView animateWithDuration:0.33 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ label.alpha = 0.0; CGRect orig=label.frame; label.frame=CGRectMake(label.frame.origin.x+25, label.frame.origin.y, label.frame.size.width, label.frame.size.height); label.alpha = 1.0; label.frame=orig; } completion:nil]; UIBarButtonItem *backButton =[[UIBarButtonItem alloc] initWithCustomView:view]; } - (void) handleBack:(id)sender{ } 

EDITAR:

En lugar de agregar el botón, en mi opinión, el mejor enfoque es utilizar un reconocedor de gestos.

 UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBack:)]; [view addGestureRecognizer:tap]; [view setUserInteractionEnabled:YES]; 

No estoy seguro de si esto funcionaría, pero podría intentar crear un UINavigationController con la configuración predeterminada para crear el botón, buscar el botón en la jerarquía de subvista del controlador de navegación, llamar a removeFromSuperview en él, destruir el controlador de navegación y luego agregar el botón como una subvista de su barra de herramientas. También es posible que necesite retain y el botón antes de llamar a removeFromSuperview (y luego release después de agregarlo como subvista de su barra de herramientas) para evitar que se desasigne durante el proceso.

Para hacer un UIButton con una flecha bastante cercana (no soy un diseñador;) a la flecha trasera del sistema iOS 7:

Estándar:

Flecha trasera estándar del sistema

Apple SD Gothic Neo

Personaje de Apple SD Gothic Neo <

En Xcode:

  • Céntrese en el campo de valor del título del botón (o cualquier otra vista / control con contenido de texto)
  • Edición abierta -> Caracteres especiales
  • Seleccione el grupo de paréntesis y haga doble clic en el carácter ‘< '
  • Cambiar fuente a: Apple SD Gothic Neo, Regular con el tamaño deseado (por ejemplo, 20)
  • Cambia el color como quieras

La respuesta de Ref @ staticVoidMan a Back-like arrow en iOS 7

flecha hacia atrás

Si no desea preocuparse por los archivos de imagen, la forma de la flecha se puede dibujar en una subclase UIView con el siguiente código:

 - (void)drawRect:(CGRect)rect { float width = rect.size.width; float height = rect.size.height; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextBeginPath(context); CGContextMoveToPoint(context, width * 5.0/6.0, height * 0.0/10.0); CGContextAddLineToPoint(context, width * 0.0/6.0, height * 5.0/10.0); CGContextAddLineToPoint(context, width * 5.0/6.0, height * 10.0/10.0); CGContextAddLineToPoint(context, width * 6.0/6.0, height * 9.0/10.0); CGContextAddLineToPoint(context, width * 2.0/6.0, height * 5.0/10.0); CGContextAddLineToPoint(context, width * 6.0/6.0, height * 1.0/10.0); CGContextClosePath(context); CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); CGContextFillPath(context); } 

donde la vista de flecha es proporcional a un ancho de 6.0 y una altura de 10.0

  self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem; 

Funciona para mi. Lo usé cuando tenía más tabs que cabían en la barra de tabs, y un controlador de vista insertado desde “Más” anuló LeftBarButtonItem en su viewDidLoad.

Puede encontrar las imágenes de origen extrayéndolas de Other.artwork en UIKit $ {SDKROOT} /System/Library/Frameworks/UIKit.framework/Other.artwork. La comunidad de modding tiene algunas herramientas para extraerlos, aquí . Una vez que extrae la imagen, puede escribir un código para volver a colorearlo según sea necesario y configurarlo como la imagen del botón. Si puede o no enviar tal cosa (ya que está incorporando obras de arte derivadas) podría ser un poco arriesgado, entonces tal vez quiera hablar con un abogado.

La biblioteca Three20 tiene una forma de hacer esto:

  UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle: @"Title" style:UIBarButtonItemStylePlain target:self action:@selector(foo)]; UIColor* darkBlue = RGBCOLOR(109, 132, 162); TTShapeStyle* style = [TTShapeStyle styleWithShape:[TTRoundedLeftArrowShape shapeWithRadius:4.5] next: [TTShadowStyle styleWithColor:RGBCOLOR(255,255,255) blur:1 offset:CGSizeMake(0, 1) next: [TTReflectiveFillStyle styleWithColor:darkBlue next: [TTBevelBorderStyle styleWithHighlight:[darkBlue shadow] shadow:[darkBlue multiplyHue:1 saturation:0.5 value:0.5] width:1 lightSource:270 next: [TTInsetStyle styleWithInset:UIEdgeInsetsMake(0, -1, 0, -1) next: [TTBevelBorderStyle styleWithHighlight:nil shadow:RGBACOLOR(0,0,0,0.15) width:1 lightSource:270 next:nil]]]]]]; TTView* view = [[[TTView alloc] initWithFrame:CGRectMake(0, 0, 80, 35)] autorelease]; view.backgroundColor = [UIColor clearColor]; view.style = style; backButton.customView = view; self.navigationItem.leftBarButtonItem = backButton; 

Descubrí que con el siguiente código simple funcionaba el truco (requiere una imagen personalizada en el paquete):

 // Creates a back button instead of default behaviour (displaying title of previous screen) UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_arrow.png"] style:UIBarButtonItemStyleBordered target:self action:@selector(backAction)]; tipsDetailViewController.navigationItem.leftBarButtonItem = backButton; [backButton release]; 

Esto es lo que terminé haciendo después de buscar a través de todas estas soluciones y otras. Utiliza un png estirable extraído de las imágenes de stock UIKit. De esta forma puedes configurar el texto para lo que sea que tengas

 // Generate the background images UIImage *stretchableBackButton = [[UIImage imageNamed:@"UINavigationBarDefaultBack.png"] stretchableImageWithLeftCapWidth:14 topCapHeight:0]; UIImage *stretchableBackButtonPressed = [[UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"] stretchableImageWithLeftCapWidth:13 topCapHeight:0]; // Setup the UIButton UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; [backButton setBackgroundImage:stretchableBackButton forState:UIControlStateNormal]; [backButton setBackgroundImage:stretchableBackButtonPressed forState:UIControlStateSelected]; NSString *buttonTitle = NSLocalizedString(@"Back", @"Back"); [backButton setTitle:buttonTitle forState:UIControlStateNormal]; [backButton setTitle:buttonTitle forState:UIControlStateSelected]; backButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 2, 1); // Tweak the text position NSInteger width = ([backButton.titleLabel.text sizeWithFont:backButton.titleLabel.font].width + backButton.titleEdgeInsets.right +backButton.titleEdgeInsets.left); [backButton setFrame:CGRectMake(0, 0, width, 29)]; backButton.titleLabel.font = [UIFont boldSystemFontOfSize:13.0f]; [backButton addTarget:self action:@selector(yourSelector:) forControlEvents:UIControlEventTouchDown]; // Now add the button as a custom UIBarButtonItem UIBarButtonItem *backButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:backButton] autorelease]; self.navigationItem.leftBarButtonItem = backButtonItem; 

Es fácil de hacer con Interface Builder en Xcode 5.x

Resultado

  • utilice la barra de herramientas y el elemento del botón de barra de la biblioteca de objetos

    Componentes

  • en la sección Editar imagen de la sección Inspector de atributos del botón con la imagen del botón Atrás

    Inspector de atributos

¡Hecho!

Intentaba hacer lo mismo, pero quería que el botón Atrás estuviera en la barra de navegación. (De hecho, necesitaba un botón de retroceso, que haría más que solo retroceder, así que tuve que usar la propiedad leftBarButtonItem). Probé lo que sugirió AndrewS, pero en la barra de navegación no se vería como debería, ya que el UIButton se convirtió en un UIBarButtonItem.

Pero encontré una manera de evitar esto. De hecho, solo puse una UIView debajo de UIButton y configuré la vista personalizada para UIBarButtonItem. Aquí está el código, si alguien lo necesita:

 // initialize button and button view UIButton *backButton = [UIButton buttonWithType:101]; UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, backButton.frame.size.width, backButton.frame.size.height)]; [backButton addTarget:self action:@selector(backButtonTouched:) forControlEvents:UIControlEventTouchUpInside]; [backButton setTitle:@"Back" forState:UIControlStateNormal]; [backButtonView addSubview:backButton]; // set buttonview as custom view for bar button item UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButtonView]; self.navigationItem.leftBarButtonItem = backButtonItem; // push item to navigationbar items [self.navigationController.navigationBar setItems:[NSArray arrayWithObject:backButtonItem]]; 

Para crear una imagen para el UIToolbar, haga un png en photoshop y DONDE SIEMPRE hay CUALQUIER color lo pone blanco, y donde es alfa = 0 entonces lo deja solo.

El SDK de hecho coloca el borde alrededor del ícono que ha creado y lo vuelve blanco sin que tenga que hacer nada.

Mira, esto es lo que hice en Photoshop para mi botón de reenvío (obviamente, cambiarlo por el botón Atrás):

http://twitpic.com/1oanv

y así es como apareció en Interface Builder

http://twitpic.com/1oaoa

Solución SIN usar png. En base a esta respuesta SO: Agregar la pequeña flecha al lado derecho de una celda en una Celda TableView de iPhone

¡Simplemente volteando el UITableViewCell horizontalmente!

 UIButton *btnBack = [[UIButton alloc] initWithFrame:CGRectMake(0, 5, 70, 20)]; // Add the disclosure CGRect frm; UITableViewCell *disclosure = [[UITableViewCell alloc] init]; disclosure.transform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1); frm = self.btnBack.bounds; disclosure.frame = CGRectMake(frm.origin.x, frm.origin.y, frm.size.width-25, frm.size.height); disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator; disclosure.userInteractionEnabled = NO; [self.btnBack addSubview:disclosure]; // Add the label UILabel *lbl = [[UILabel alloc] init]; frm = CGRectOffset(self.btnBack.bounds, 15, 0); lbl.frame = frm; lbl.textAlignment = NSTextAlignmentCenter; lbl.text = @"BACK"; [self addSubview:lbl]; 

Si quiere evitar dibujarlo usted mismo, puede usar la clase no documentada: UINavigationButton con estilo 1. Esto podría, por supuesto, evitar que su aplicación sea aprobada … / John

Bueno, no tienes que tener un botón diferente para cada tamaño, puedes usar [UIImage stretchableImageWithLeftCapWidth:topCapHeight:] , pero lo único que he encontrado son imágenes personalizadas.

Tuve un problema similar y salí de una biblioteca PButton . Y la muestra es el botón con el botón de navegación hacia atrás, que se puede usar en cualquier lugar como un botón personalizado.

Algo como esto: enter image description here

Ejemplo en Swift 3, con un botón anterior y uno siguiente en la parte superior derecha.

 let prevButtonItem = UIBarButtonItem(title: "\u{25C0}", style: .plain, target: self, action: #selector(prevButtonTapped)) let nextButtonItem = UIBarButtonItem(title: "\u{25B6}", style: .plain, target: self, action: #selector(nextButtonTapped)) self.navigationItem.rightBarButtonItems = [nextButtonItem, prevButtonItem] 

Rápido

 // create button var backButton = UIButton(type: 101) // left-pointing shape! backButton.addTarget(self, action: #selector(self.backAction), for: .touchUpInside) backButton.setTitle("Back", for: .normal) // create button item -- possible because UIButton subclasses UIView! var backItem = UIBarButtonItem(customView: backButton) // add to toolbar, or to a navbar (you should only have one of these!) toolbar.items = [backItem] navItem.leftBarButtonItem = backItem 

Prueba esto. Estoy seguro de que no necesita una imagen del botón de retroceso para crear una.

 UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(yourSelectorGoesHere:)]; self.navigationItem.backBarButtonItem = backButton; 

Eso es todo lo que tienes que hacer 🙂

¿Por qué estás haciendo esto? Si desea algo que se parece a una barra de navegación, use UINavigationBar.

Las barras de herramientas tienen un estilo visual específico asociado a ellas. Las pautas de interfaz humana para el estado de iPhone:

Aparece una barra de herramientas en el borde inferior de la pantalla y contiene botones que realizan acciones relacionadas con objetos en la vista actual.

Luego da varios ejemplos visuales de icons aproximadamente cuadrados sin texto. Te insto a que sigas el HIG en esto.