ios - guidelines - Usar el icono UIBarButtonItem en UIButton
menu ios (8)
2017/10/05 no funciona en iOS 11.0.1
para swift 3/4 (llámalo en el hilo principal)
extension UIBarButtonSystemItem {
func image() -> UIImage? {
let tempItem = UIBarButtonItem(barButtonSystemItem: self,
target: nil,
action: nil)
// add to toolbar and render it
let bar = UIToolbar()
bar.setItems([tempItem],
animated: false)
bar.snapshotView(afterScreenUpdates: true)
// got image from real uibutton
let itemView = tempItem.value(forKey: "view") as! UIView
for view in itemView.subviews {
if let button = view as? UIButton,
let image = button.imageView?.image {
return image.withRenderingMode(.alwaysTemplate)
}
}
return nil
}
}
UIBarButtonSystemItem.play.image()
Para Objective-C:
+ (UIImage *)imageFromSystemBarButton:(UIBarButtonSystemItem)systemItem {
UIBarButtonItem* tempItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:systemItem target:nil action:nil];
// Add to toolbar and render it
UIToolbar *bar = [[UIToolbar alloc] init];
[bar setItems:@[tempItem] animated:NO];
[bar snapshotViewAfterScreenUpdates:YES];
// Get image from real UIButton
UIView *itemView = [(id)tempItem view];
for (UIView* view in itemView.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
return [(UIButton*)view imageForState:UIControlStateNormal];
}
}
return nil;
}
UIBarButtonItem
tiene varios iconos disponibles. ¿Es posible usar el icono que aparece después de configurar su identificador en ''basura'':
con un UIButton
? No hay un método directo para hacer eso como configurar el identificador o el estilo .
Aquí hay una solución que funciona con CUALQUIER elemento del botón de la barra del sistema + que admite tintColor
:
- (void)viewDidLoad {
[super viewDidLoad];
[self.button setImage:[self imageFromSystemBarButton:UIBarButtonSystemItemTrash]
forState:UIControlStateNormal];
self.button.tintColor = [UIColor redColor];
}
- (UIImage *)imageFromSystemBarButton:(UIBarButtonSystemItem)systemItem {
// Holding onto the oldItem (if any) to set it back later
// could use left or right, doesn''t matter
UIBarButtonItem *oldItem = self.navigationItem.rightBarButtonItem;
UIBarButtonItem *tempItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:systemItem
target:nil
action:nil];
// Setting as our right bar button item so we can traverse its subviews
self.navigationItem.rightBarButtonItem = tempItem;
// Don''t know whether this is considered as PRIVATE API or not
UIView *itemView = (UIView *)[self.navigationItem.rightBarButtonItem performSelector:@selector(view)];
UIImage *image = nil;
// Traversing the subviews to find the ImageView and getting its image
for (UIView *subView in itemView.subviews) {
if ([subView isKindOfClass:[UIImageView class]]) {
image = ((UIImageView *)subView).image;
break;
}
}
// Setting our oldItem back since we have the image now
self.navigationItem.rightBarButtonItem = oldItem;
return image;
}
PS Siéntete libre de mejorar si conoces una mejor manera, gracias.
Como ya se mencionó en los comentarios a la respuesta de @Islam Q, la solución presentada podría fallar, si el UINavigationItem no se muestra actualmente en pantalla. Falla, por ejemplo, si el controlador de vista no está cargado actualmente. De hecho, el problema parece ser el diseño faltante de la barra UINavigation en estos casos.
Una versión más ''a prueba de balas'' sería utilizar un objeto UINavigationBar creado especialmente para obtener las imágenes de los elementos del sistema. Esto también haría que guardar el guardado y la restauración de cualquier UIBarButtonItems existente sea obsoleto.
He empaquetado esto en una pequeña clase de ayuda:
LEABarButtonSystemItemImage.h:
#import <UIKit/UIKit.h>
/**
LEABarButtonSystemItemImage interface
*/
@interface LEABarButtonSystemItemImage : NSObject
+ (UIImage *)imageFromBarButtonSystemItem:(UIBarButtonSystemItem)pBarButtonSystemItem;
+ (UIImage *)customImageForBarButtonSystemItem:(UIBarButtonSystemItem)pBarButtonSystemItem;
+ (NSDictionary<__kindof NSNumber*, __kindof UIImage*> *)barButtonItemImages;
@end
LEABarButtonSystemItemImage.m
#import "LEABarButtonSystemItemImage.h"
/**
LEABarButtonSystemItemImage implementation
*/
@implementation LEABarButtonSystemItemImage
/*
imageFromBarButtonSystemItem:
*/
+ (UIImage *)imageFromBarButtonSystemItem:(UIBarButtonSystemItem)pBarButtonSystemItem {
static const CGFloat defaultNBBtnHW = 44.0;
UINavigationBar * tempNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, defaultNBBtnHW, defaultNBBtnHW)];
UINavigationItem * tempNavigationItem = [[UINavigationItem alloc] init];
UIBarButtonItem * tempBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:pBarButtonSystemItem target:nil action:NULL];
tempNavigationBar.items = @[tempNavigationItem];
tempNavigationItem.rightBarButtonItems = @[tempBarButtonItem];
UIImage * barButtonSystemItemImage = nil;
@try {
UIView * barButtonItemView = [tempBarButtonItem valueForKey:@"view"];
for (UIView* subview in barButtonItemView.subviews) {
if ([subview isKindOfClass:UIImageView.class]) {
barButtonSystemItemImage = ((UIImageView *)subview).image;
break;
}
}
} @catch (...) { NSLog(@"%s: Exception while retrieving image from UIBarButtonItem!", __PRETTY_FUNCTION__); }
return (barButtonSystemItemImage ?: [LEABarButtonSystemItemImage customImageForBarButtonSystemItem:pBarButtonSystemItem]);
}
/*
customImageForBarButtonSystemItem:
*/
+ (UIImage *)customImageForBarButtonSystemItem:(UIBarButtonSystemItem)pBarButtonSystemItem {
NSString * customBarButtonSystemItemImageName = nil;
switch (pBarButtonSystemItem) {
case UIBarButtonSystemItemDone: customBarButtonSystemItemImageName = @"customBarButtonSystemItemDone"; break;
case UIBarButtonSystemItemCancel: customBarButtonSystemItemImageName = @"customBarButtonSystemItemCancel"; break;
case UIBarButtonSystemItemEdit: customBarButtonSystemItemImageName = @"customBarButtonSystemItemEdit"; break;
case UIBarButtonSystemItemSave: customBarButtonSystemItemImageName = @"customBarButtonSystemItemSave"; break;
case UIBarButtonSystemItemAdd: customBarButtonSystemItemImageName = @"customBarButtonSystemItemAdd"; break;
case UIBarButtonSystemItemCompose: customBarButtonSystemItemImageName = @"customBarButtonSystemItemCompose"; break;
case UIBarButtonSystemItemReply: customBarButtonSystemItemImageName = @"customBarButtonSystemItemReply"; break;
case UIBarButtonSystemItemAction: customBarButtonSystemItemImageName = @"customBarButtonSystemItemAction"; break;
case UIBarButtonSystemItemOrganize: customBarButtonSystemItemImageName = @"customBarButtonSystemItemOrganize"; break;
case UIBarButtonSystemItemBookmarks: customBarButtonSystemItemImageName = @"customBarButtonSystemItemBookmarks"; break;
case UIBarButtonSystemItemSearch: customBarButtonSystemItemImageName = @"customBarButtonSystemItemSearch"; break;
case UIBarButtonSystemItemRefresh: customBarButtonSystemItemImageName = @"customBarButtonSystemItemRefresh"; break;
case UIBarButtonSystemItemStop: customBarButtonSystemItemImageName = @"customBarButtonSystemItemStop"; break;
case UIBarButtonSystemItemCamera: customBarButtonSystemItemImageName = @"customBarButtonSystemItemCamera"; break;
case UIBarButtonSystemItemTrash: customBarButtonSystemItemImageName = @"customBarButtonSystemItemTrash"; break;
case UIBarButtonSystemItemPlay: customBarButtonSystemItemImageName = @"customBarButtonSystemItemPlay"; break;
case UIBarButtonSystemItemPause: customBarButtonSystemItemImageName = @"customBarButtonSystemItemPause"; break;
case UIBarButtonSystemItemRewind: customBarButtonSystemItemImageName = @"customBarButtonSystemItemRewind"; break;
case UIBarButtonSystemItemFastForward: customBarButtonSystemItemImageName = @"customBarButtonSystemItemFastForward"; break;
case UIBarButtonSystemItemUndo: customBarButtonSystemItemImageName = @"customBarButtonSystemItemUndo"; break;
case UIBarButtonSystemItemRedo: customBarButtonSystemItemImageName = @"customBarButtonSystemItemRedo"; break;
case UIBarButtonSystemItemPageCurl: customBarButtonSystemItemImageName = @"customBarButtonSystemItemPageCurl"; break;
default: break;
}
return (customBarButtonSystemItemImageName
? [UIImage imageNamed:customBarButtonSystemItemImageName]
: nil);
}
/*
barButtonItemImages
*/
+ (NSDictionary<__kindof NSNumber*, __kindof UIImage*> *)barButtonItemImages {
NSMutableDictionary<__kindof NSNumber*, __kindof UIImage*> * barButtonItemImages = [NSMutableDictionary dictionary];
// From: https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIBarButtonItem.h
// unsigned int systemItem : 7;
for (NSUInteger uIndex = 0; uIndex < (1<<7); ++uIndex) {
UIImage* systemImage = [LEABarButtonSystemItemImage imageFromBarButtonSystemItem:uIndex];
if (systemImage) {
[barButtonItemImages setObject:systemImage forKey:@(uIndex)];
}
}
NSLog(@"%s: %@", __PRETTY_FUNCTION__, barButtonItemImages);
return barButtonItemImages;
}
@end
Como complemento / reserva, el método devuelve una imagen personalizada, si no se puede recuperar una imagen del elemento del sistema. Por supuesto, estas imágenes personalizadas deben estar presentes en el paquete de aplicaciones.
El último método ''barButtonImages'' se implementó solo por curiosidad ... en el encabezado UIBarButtonItem se declara que el miembro systemItem usa 7 bits (0..127). Actualmente solo se documentan 22 valores desde UIBarButtonSystemItemDone a UIBarButtonItemSystemItemPageCurl ... y de hecho; Encontré algunas imágenes no documentadas que comienzan con índices por encima de 100 (probado en iOS 9.3 en el simulador 6S +) :-)
Descargue la imagen desde algún lugar de la web, agréguela a su proyecto y configure la imagen de UIButton
a la imagen que acaba de descargar.
No encontré lo mismo que Apple está usando pero encontré este . Simplemente cambia su color en Pixelmator o Photoshop.
Lo estaba usando para imageView en la celda de la tabla y, de alguna manera, el color de tinte no funcionaba donde lo configuré ... Así que terminé con este código donde configuraste el color para la imagen.
+ (UIImage *)imageFromSystemBarButton:(UIBarButtonSystemItem)systemItem :(UIColor *) color {
UIToolbar *bar = UIToolbar.new;
UIBarButtonItem *buttonItem = [UIBarButtonItem createWithItem:systemItem];
[bar setItems:@[buttonItem] animated:NO];
[bar snapshotViewAfterScreenUpdates:YES];
for (UIView *view in [(id) buttonItem view].subviews)
if ([view isKindOfClass:UIButton.class]) {
UIImage *image = [((UIButton *) view).imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
[color set];
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
return nil;
}
Sobre la base de la respuesta de @yycking, escribí una extensión Swift 3/4 adecuada:
//
// UIImage+imageFromSystemBarButton.swift
//
import UIKit
extension UIImage{
class func imageFromSystemBarButton(_ systemItem: UIBarButtonSystemItem, renderingMode:UIImageRenderingMode = .automatic)-> UIImage {
let tempItem = UIBarButtonItem(barButtonSystemItem: systemItem, target: nil, action: nil)
// add to toolbar and render it
let bar = UIToolbar()
bar.setItems([tempItem], animated: false)
bar.snapshotView(afterScreenUpdates: true)
// got image from real uibutton
let itemView = tempItem.value(forKey: "view") as! UIView
for view in itemView.subviews {
if view is UIButton {
let button = view as! UIButton
let image = button.imageView!.image!
image.withRenderingMode(renderingMode)
return image
}
}
return UIImage()
}
}
Ejemplo con botón de acción (coloración por defecto):
let actionImage = UIImage.imageFromSystemBarButton(.action)
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
myButton.setImage(actionImage, for: .normal)
view.addSubview(myButton)
Si desea que su imagen siempre se trate como una plantilla, independientemente del contexto, configure renderingMode en .alwaysTemplate
let actionImage = UIImage.imageFromSystemBarButton(.action, renderingMode: .alwaysTemplate)
Todos los íconos del sistema iOS se pueden extraer mediante una aplicación pequeña y práctica llamada iOS Artwork Extractor. Lo uso todo el tiempo cuando quiero imitar los comportamientos del sistema iOS.
Descargue el proyecto Xcode en:
Usando Quartz2D con Swift 4.2
Las soluciones basadas en una extensión para extraer la imagen del UIBarButtonSystemItem
no funcionan en iOS 11/12, así que decidí agregar una clase personalizada para dibujar los iconos sin agregar ningún .png
Esto se implementa para .trash y .action que son los íconos que necesito en mi proyecto. Siéntete libre de añadir el resto.
Úselo de la siguiente manera (debe cumplir con el protocolo SystemIConDelegate
, establecer la propiedad Delegate y agregar el método requerido):
let trashIcon = SystemIcon(withType: .trash) trashIcon.delegate = self shareButton = UIButton() shareButton.addSubview(trashIcon)
La clase SystemIcon
está aquí. Está optimizado para 30 x 30 puntos:
import UIKit protocol SystemIconDelegate { func systemIconButtonClicked() } class SystemIcon: UIView { var type: UIBarButtonItem.SystemItem! let color = UIColor.blue var delegate: SystemIconDelegate? convenience init(withType: UIBarButtonItem.SystemItem) { self.init(frame: CGRect(x: 0, y: 0, width: 30, height: 30)) self.backgroundColor = .clear self.type = withType } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.delegate?.systemIconButtonClicked() } override func draw(_ rect: CGRect) { let w = self.frame.width let h = self.frame.height let context = UIGraphicsGetCurrentContext() context?.setStrokeColor(color.cgColor) context?.setLineWidth(1.0) switch type! { case .action: //Box context?.stroke(CGRect(x: w * 0.16, y: h * 0.3, width: w * 0.69, height: h * 0.69)) context?.setFillColor(UIColor.white.cgColor) context?.fill(CGRect(x: w * 0.4, y: 0, width: w * 0.2, height: h * 0.5)) //Arrow context?.move(to: CGPoint(x: w * 0.5, y: h * 0.02)) context?.addLine(to: CGPoint(x: w * 0.5, y: h * 0.64)) context?.move(to: CGPoint(x: w * 0.33, y: h * 0.19)) context?.addLine(to: CGPoint(x: w * 0.5, y: h * 0.02)) context?.addLine(to: CGPoint(x: w * 0.67, y: h * 0.19)) context?.strokePath() case .trash: context?.move(to: CGPoint(x: w * 0.1, y: h * 0.15)) context?.addLine(to: CGPoint(x: w * 0.9, y: h * 0.15)) //Can context?.move(to: CGPoint(x: w * 0.2, y: h * 0.15)) context?.addArc(tangent1End: CGPoint(x: w * 0.25, y: h * 0.95), tangent2End: CGPoint(x: w * 0.5, y:h * 0.95), radius: CGFloat.x(2.0)) context?.addArc(tangent1End: CGPoint(x: w * 0.75, y: h * 0.95), tangent2End: CGPoint(x: w * 0.8, y: h * 0.15), radius: CGFloat.x(2.0)) context?.addLine(to: CGPoint(x: w * 0.8, y: h * 0.15)) // Handle context?.move(to: CGPoint(x: w * 0.34, y: h * 0.15)) context?.addArc(tangent1End: CGPoint(x: w * 0.34, y: h * 0.02), tangent2End: CGPoint(x: w * 0.5, y: h * 0.02), radius: CGFloat.x(2.0)) context?.addArc(tangent1End: CGPoint(x: w * 0.66, y : h * 0.02), tangent2End: CGPoint(x: w * 0.66, y: h * 0.15), radius: CGFloat.x(2.0)) context?.addLine(to: CGPoint(x: w * 0.66, y: h * 0.15)) //Lines context?.move(to: CGPoint(x: w * 0.35, y: h * 0.25)) context?.addLine(to: CGPoint(x: w * 0.38, y: h * 0.8)) context?.move(to: CGPoint(x: w * 0.5, y: h * 0.25)) context?.addLine(to: CGPoint(x: w * 0.5, y: h * 0.8)) context?.move(to: CGPoint(x: w * 0.65, y: h * 0.25)) context?.addLine(to: CGPoint(x: w * 0.62, y: h*0.8)) default: break } context?.strokePath() } }