UIBarButtonItem
a plusieurs icônes disponibles. Est-il possible d'utiliser l'icône qui apparaît après avoir défini son identifiant sur 'corbeille':
avec un UIButton
? Il n’existe pas de méthode simple pour le faire, comme définir l’identificateur identifiant ou style .
Téléchargez l'image quelque part sur le Web, ajoutez-la à votre projet et définissez l'image UIButton
sur celle que vous venez de télécharger.
Je n'ai pas trouvé le même produit qu'Apple mais j'ai trouvé celui-ci . Changez simplement sa couleur dans Pixelmator ou Photoshop.
Voici une solution qui fonctionne avecANYélément de bouton de la barre système + il supporte 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;
}
P.S. N'hésitez pas à vous améliorer si vous connaissez une meilleure solution, merci.
Sur la base de la réponse @yycking, j’ai écrit une extension Swift 4 appropriée:
// UIImage+FromSystemItem.Swift
import UIKit
extension UIImage {
public convenience init?(systemItem sysItem: UIBarButtonItem.SystemItem, renderingMode:UIImage.RenderingMode = .automatic) {
guard let sysImage = UIImage.imageFromSystemItem(sysItem, renderingMode: renderingMode)?.cgImage else {
return nil
}
self.init(cgImage: sysImage)
}
private class func imageFromSystemItem(_ systemItem: UIBarButtonItem.SystemItem, renderingMode:UIImage.RenderingMode = .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 nil
}
}
Exemple avec le bouton d'action (coloration par défaut):
let actionImage = UIImage(systemItem: .action)
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
myButton.setImage(actionImage, for: .normal)
view.addSubview(myButton)
Si vous voulez que votre image soit toujours traitée comme un modèle, peu importe du contexte, définissez renderingMode sur .alwaysTemplate
let actionImage = UIImage(systemItem: .action, renderingMode: .alwaysTemplate)
Comme déjà mentionné dans les commentaires sur la réponse de @Islam Q, la solution présentée peut échouer si le UINavigationItem n'est pas affiché à l'écran. Il échoue, par exemple, si le contrôleur de vue n'est pas actuellement chargé. En fait, le problème semble être la structure manquante de UINavigationBar dans ces cas.
Une version plus «résistante aux balles» consisterait à utiliser un objet UINavigationBar spécialement créé pour obtenir les images d'élément système. Cela rendrait également l'enregistrement et la restauration de tout UIBarButtonItems existant obsolète.
J'ai mis cela dans une petite classe d'aide:
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
En tant qu'add-on/fallback, la méthode renvoie une image personnalisée, si aucune image d'élément système n'a pu être récupérée. Bien entendu, ces images personnalisées doivent être présentes dans l'ensemble d'applications.
La dernière méthode 'barButtonImages' a été implémentée juste par curiosité ... dans l'en-tête UIBarButtonItem, le membre systemItem est déclaré comme utilisant 7 bits (0..127). Actuellement, seules 22 valeurs sont documentées de UIBarButtonSystemItemDone à UIBarButtonItemSystemItemPageCurl ... et en fait; J'ai trouvé des images non documentées commençant par des index supérieurs à 100 (testées sur iOS 9.3 dans le simulateur 6S +) :-)
Toutes les icônes du système iOS peuvent être extraites à l'aide d'une petite application très pratique appelée iOS Artwork Extractor. Je l'utilise tout le temps lorsque je veux imiter les comportements du système iOS.
Téléchargez le projet Xcode sur:
Utilisation de Quartz2D avec Swift 4.2
Les solutions basées sur une extension permettant d'extraire l'image de la UIBarButtonSystemItem
ne fonctionnent pas dans iOS 11/12, alors j'ai décidé d'ajouter une classe personnalisée pour dessiner les icônes sans ajouter de fichier .png.
Ceci est implémenté pour .trash et .action, qui sont les icônes dont j'ai besoin dans mon projet. N'hésitez pas à ajouter le reste.
Utilisez-le comme suit (vous devez vous conformer au protocole SystemIConDelegate
, définir la propriété Delegate et ajouter la méthode requise):
let trashIcon = SystemIcon(withType: .trash)
trashIcon.delegate = self
shareButton = UIButton()
shareButton.addSubview(trashIcon)
La classe SystemIcon
est ici. Il est optimisé pour 30 X 30 points:
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()
}
}
Je l'utilisais pour imageView dans une cellule de tableau et la teinte couleur ne fonctionnait pas où que je sois configurée ... Je me suis donc retrouvé avec ce code dans lequel vous définissez la couleur de l'image.
+ (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;
}
Basé sur @yycking answer , voici le port Xamarin.iOS C #:
[DllImport (Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
static extern IntPtr IntPtr_objc_msgSend (IntPtr receiver, IntPtr selector);
public static UIImage GetImage (UIBarButtonSystemItem systemItem)
{
var tempItem = new UIBarButtonItem (systemItem);
// Add to toolbar and render it
var bar = new UIToolbar ();
bar.SetItems (new [] { tempItem }, false);
bar.SnapshotView (true);
// Get image from real UIButton
var selHandle = Selector.GetHandle ("view");
var itemView = Runtime.GetNSObject<UIView> (IntPtr_objc_msgSend (tempItem.Handle, selHandle));
foreach (var view in itemView?.Subviews) {
if (view is UIButton button)
return button.ImageForState (UIControlState.Normal);
}
return null;
}