web-dev-qa-db-ja.com

UIButtonでUIBarButtonItemアイコンを使用

UIBarButtonItemには複数のアイコンがあります。識別子を「ゴミ箱」に設定した後に表示されるアイコンを使用することは可能ですか?

trash icon

UIButtonidentifierまたはstyleを設定するような簡単な方法はありません。

33
ZviBar

Webのどこかから画像をダウンロードし、プロジェクトに追加して、UIButtonの画像をダウンロードした画像に設定します。

Appleが使用されているのと同じものは見つかりませんでしたが、 this one が見つかりました。PixelmatorまたはPhotoshopで色を変更するだけです。

9
yoeriboven

for 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()

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;
}
_
23
yycking

[〜#〜] any [〜#〜]システムバーボタンアイテム+ 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;
}


追伸:より良い方法を知っていれば、お気軽に改善してください、ありがとう。

15
Islam Q.

@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
    }
}

アクションボタンの例(デフォルトの色付け):

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)

画像がコンテキストに関係なく常にテンプレートとして扱われるようにするには、renderingModeを。alwaysTemplateに設定します

 let actionImage = UIImage(systemItem: .action, renderingMode: .alwaysTemplate) 
8
Peter Kreinz

@Islam Qの回答に対するコメントで既に述べたように、INavigationItemが現在画面上にレンダリングされていない場合、そこに提示されたソリューションは失敗する可能性があります。たとえば、View Controllerが現在ロードされていない場合、失敗します。実際、これらのケースでは、問題はINavigationBarのレイアウトが欠落しているようです。

より「防弾」バージョンは、特別に作成されたUINavigationBarオブジェクトを使用して、システムアイテムの画像を取得することです。これにより、既存のUIBarButtonItemsの保存と復元が廃止されます。

これを小さなヘルパークラスにまとめました。

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

Add on/fallbackとして、システムアイテムの画像を取得できない場合、メソッドはカスタム画像を返します。もちろん、これらのカスタム画像はアプリバンドルに存在する必要があります。

最後のメソッド 'barButtonImages'は、好奇心のために実装されました... UIBarButtonItemヘッダーでは、メンバーsystemItemは7ビット(0..127)を使用するように宣言されています。現在、UIBarButtonSystemItemDoneからUIBarButtonItemSystemItemPageCurl ...に文書化されている値は22のみです。実際、 100を超えるインデックスで始まるドキュメント化されていない画像をいくつか見つけました(6S +シミュレーターのiOS 9.3でテスト済み):-)

4
LaborEtArs

すべてのiOSシステムアイコンは、iOS Artwork Extractorと呼ばれる便利な小さなアプリを使用して抽出できます。 iOSシステムの振る舞いを真似たいときはいつも使っています。

Xcodeプロジェクトを次からダウンロードします。

https://github.com/0xced/iOS-Artwork-Extractor

3
DKLA

私はそれをテーブルセルの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;
}
1
Renetik

@yycking answer に基づいて、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;
}
1
dalexsoto

Swift 4.2でのQuartz2Dの使用

UIBarButtonSystemItemから画像を抽出する拡張機能に基づくソリューションはiOS 11/12では機能しないため、.pngを追加せずにアイコンを描画するカスタムクラスを追加することにしました

enter image description here

これは、プロジェクトで必要なアイコンである.trashと.actionに対して実装されています。残りを自由に追加してください。

次のように使用します(SystemIConDelegateプロトコルに準拠し、Delegateプロパティを設定し、必要なメソッドを追加する必要があります)。

let trashIcon = SystemIcon(withType: .trash)
trashIcon.delegate = self
shareButton = UIButton()
shareButton.addSubview(trashIcon)

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()
    }
}
1
eharo2