ios 在 UIButton 中使用 UIBarButtonItem 图标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21187885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use UIBarButtonItem icon in UIButton
提问by ZviBar
UIBarButtonItem
has multiple icons available. Is it possible to use the icon which appears after setting its identifier to 'trash':
UIBarButtonItem
有多个图标可用。是否可以使用将其标识符设置为“垃圾”后出现的图标:
with an UIButton
? There is no straighforward method to do that like setting the identifieror style.
用UIButton
? 没有像设置identifier或style那样直接的方法来做到这一点。
采纳答案by yoeriboven
Download the image from somewhere on the web, add it to your project and set the UIButton
's image to the image you just downloaded.
从网络上的某个位置下载图像,将其添加到您的项目中,并将UIButton
的图像设置为您刚刚下载的图像。
I did not find the same as Apple is using but I found this one. Simply change it's color in Pixelmator or Photoshop.
我没有找到与 Apple 使用的相同,但我找到了这个。只需在 Pixelmator 或 Photoshop 中更改它的颜色即可。
回答by yycking
NewiOS 13 support SF SymbolsnowUIImage(systemName: "trash")
新的iOS 13现在支持SF SymbolsUIImage(systemName: "trash")
for swift 4.2 (call it on main thread)
对于 swift 4.2 (在主线程上调用它)
extension UIBarButtonItem.SystemItem {
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()
UIBarButtonSystemItem.play.image()
For Objective-C:
对于 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;
}
回答by Islam Q.
Here's a solution that works with ANYSystem bar button item + it supports tintColor
:
这是一个适用于任何系统栏按钮项+它支持的解决方案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. Feel free to improve if you know of a better way, thanks.
PS 如果您知道更好的方法,请随时改进,谢谢。
回答by Peter Kreinz
Based on @yycking answer, i wrote an suitable Swift 4extension:
基于@yycking 的回答,我编写了一个合适的Swift 4扩展:
// 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
}
}
Example with action button (default coloring):
操作按钮示例(默认颜色):
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)
If you want your image to always be treated as a template regardless of context, set renderingMode to .alwaysTemplate
如果您希望无论上下文如何始终将图像视为模板,请将renderMode设置为.alwaysTemplate
let actionImage = UIImage(systemItem: .action, renderingMode: .alwaysTemplate)
回答by DKLA
All the iOS system icons can be extracted using a handy little app called (fittingly enough) iOS Artwork Extractor. I use it all the time when I want to mimic iOS system behaviors.
所有 iOS 系统图标都可以使用一个名为(非常合适)iOS Artwork Extractor 的方便的小应用程序提取。当我想模仿 iOS 系统行为时,我一直使用它。
Download the Xcode project at:
在以下位置下载 Xcode 项目:
回答by LaborEtArs
As already mentioned in the comments to @Islam Q's answer, the there presented solution might fail, if the UINavigationItemisn't currently rendered onscreen. It fails, for example, if the view controller isn't currently loaded. In fact the problem seems to be the missing layout of the UINavigationBarin these cases.
正如在对@Islam Q 的回答的评论中已经提到的那样,如果UINavigationItem当前未在屏幕上呈现,则所提出的解决方案可能会失败。例如,如果当前未加载视图控制器,则会失败。事实上,在这些情况下,问题似乎是UINavigationBar缺少布局。
A more 'bulletproof' version would be to use a specially created UINavigationBar object just for getting the system item images. This would also make save saving and restoring of any existing UIBarButtonItems obsolete.
更“防弹”的版本是使用专门创建的 UINavigationBar 对象来获取系统项目图像。这也将使保存和恢复任何现有 UIBarButtonItems 过时。
I've packed this into a small helper class:
我已经把它打包成一个小的帮助类:
LEABarButtonSystemItemImage.h:
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
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
As an add on/fallback , the method returns an custom image, if no system item image could be retrieved. Of course these custom images must be present in the apps bundle.
作为附加/回退,如果无法检索到系统项目图像,该方法将返回自定义图像。当然,这些自定义图像必须存在于应用程序包中。
The last method 'barButtonImages' was implemented just for curiosity... in the UIBarButtonItem header the member systemItem is declared to use 7 bits (0..127). Currently only 22 values are documented from UIBarButtonSystemItemDone to UIBarButtonItemSystemItemPageCurl... and in fact; I found some undocumented images starting with indexes above 100 (tested on iOS 9.3 in the 6S+ simulator) :-)
最后一个方法“barButtonImages”的实现只是为了好奇……在 UIBarButtonItem 标头中,成员 systemItem 被声明为使用 7 位(0..127)。目前,从 UIBarButtonSystemItemDone 到 UIBarButtonItemSystemItemPageCurl 只记录了 22 个值……事实上;我发现了一些索引高于 100 的未记录图像(在 6S+ 模拟器中在 iOS 9.3 上测试):-)
回答by eharo2
Using Quartz2D with Swift 4.2
在 Swift 4.2 中使用 Quartz2D
The solutions based in an extension to extract the image from the UIBarButtonSystemItem
don't work in iOS 11/12, so I decided to add a custom class to draw the icons without adding any .png
基于从扩展中提取图像的解决方案UIBarButtonSystemItem
在 iOS 11/12 中不起作用,所以我决定添加一个自定义类来绘制图标而不添加任何 .png
This is implemented for .trash and .action that are the icons I need in my project. Feel free to add the rest.
这是为 .trash 和 .action 实现的,它们是我在项目中需要的图标。随意添加其余的。
Use it as follows (You need to conform to the SystemIConDelegate
protocol, set the Delegate property and add the required method):
使用方法如下(需要符合SystemIConDelegate
协议,设置Delegate属性并添加需要的方法):
let trashIcon = SystemIcon(withType: .trash)
trashIcon.delegate = self
shareButton = UIButton()
shareButton.addSubview(trashIcon)
The SystemIcon
class is here. It is optimized for 30 X 30 points:
该SystemIcon
班是在这里。它针对 30 X 30 点进行了优化:
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()
}
}
回答by dalexsoto
Based on @yycking answer, here is the Xamarin.iOS C# port:
基于@yycking 的回答,这里是 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;
}
回答by Renetik
I was using it for imageView in table cell and somehow tint color did not work wherever I set it... So I ended up with this code where you set color for image.
我在表格单元格中将它用于 imageView 并且不知何故在我设置它的任何地方着色颜色都不起作用......所以我最终得到了这段代码,你为图像设置了颜色。
+ (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;
}