NSToolbar
是 macOS 應用中的一個重要控制元件,用於建立視窗頂部的工具欄。工具欄通常包含按鈕和其他控制元件,使用者可以透過這些控制元件快速訪問常用功能。NSToolbar
和 NSToolbarItem
協同工作,NSToolbar
是工具欄容器,而 NSToolbarItem
是工具欄項。下面我們詳細介紹 NSToolbar
的常見 API 和基礎技巧。
基本使用
建立和初始化工具欄
Objective-C
#import <Cocoa/Cocoa.h>
// 建立一個 NSToolbar 例項
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"MainToolbar"];
// 設定 Delegate
[toolbar setDelegate:self];
// 將工具欄新增到視窗
[self.window setToolbar:toolbar];
Swift
import Cocoa
// 建立一個 NSToolbar 例項
let toolbar = NSToolbar(identifier: "MainToolbar")
// 設定 Delegate
toolbar.delegate = self
// 將工具欄新增到視窗
self.window?.toolbar = toolbar
建立工具欄項
Objective-C
// 實現 NSToolbarDelegate 方法,返回所有允許在工具欄中使用的項
- (NSArray<NSString *> *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
return @[@"FirstItem", NSToolbarFlexibleSpaceItemIdentifier, @"SecondItem"];
}
// 實現 NSToolbarDelegate 方法,為特定識別符號建立相應的工具欄項
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
if ([itemIdentifier isEqualToString:@"FirstItem"]) {
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:@"FirstItem"];
item.label = @"First";
item.toolTip = @"First Tool";
item.action = @selector(handleToolbarAction:);
item.target = self;
item.image = [NSImage imageNamed:NSImageNameAddTemplate];
return item;
} else if ([itemIdentifier isEqualToString:@"SecondItem"]) {
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:@"SecondItem"];
item.label = @"Second";
item.toolTip = @"Second Tool";
item.action = @selector(handleToolbarAction:);
item.target = self;
item.image = [NSImage imageNamed:NSImageNameRemoveTemplate];
return item;
}
return nil;
}
Swift
// 實現 NSToolbarDelegate 方法,返回所有允許在工具欄中使用的項
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [.init("FirstItem"), .flexibleSpace, .init("SecondItem")]
}
// 實現 NSToolbarDelegate 方法,為特定識別符號建立相應的工具欄項
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
if itemIdentifier.rawValue == "FirstItem" {
let item = NSToolbarItem(itemIdentifier: .init("FirstItem"))
item.label = "First"
item.toolTip = "First Tool"
item.action = #selector(handleToolbarAction(_:))
item.target = self
item.image = NSImage(named: NSImage.addTemplateName)
return item
} else if itemIdentifier.rawValue == "SecondItem" {
let item = NSToolbarItem(itemIdentifier: .init("SecondItem"))
item.label = "Second"
item.toolTip = "Second Tool"
item.action = #selector(handleToolbarAction(_:))
item.target = self
item.image = NSImage(named: NSImage.removeTemplateName)
return item
}
return nil
}
響應工具欄項點選事件
Objective-C
// 實現工具欄項的點選響應方法
- (void)handleToolbarAction:(id)sender {
NSToolbarItem *selectedItem = (NSToolbarItem *)sender;
NSLog(@"Selected item: %@", selectedItem.itemIdentifier);
}
Swift
// 實現工具欄項的點選響應方法
@objc func handleToolbarAction(_ sender: Any?) {
if let toolbarItem = sender as? NSToolbarItem {
print("Selected item: \(toolbarItem.itemIdentifier.rawValue)")
}
}
自定義工具欄項
可以透過子類化 NSToolbarItem
來建立自定義工具欄項。
Objective-C
@interface CustomToolbarItem : NSToolbarItem
@end
@implementation CustomToolbarItem
- (instancetype)initWithItemIdentifier:(NSString *)itemIdentifier {
self = [super initWithItemIdentifier:itemIdentifier];
if (self) {
// 自定義設定
self.label = @"Custom";
self.toolTip = @"Custom Tool";
self.image = [NSImage imageNamed:NSImageNameInfo];
}
return self;
}
@end
Swift
class CustomToolbarItem: NSToolbarItem {
override init(itemIdentifier: NSToolbarItem.Identifier) {
super.init(itemIdentifier: itemIdentifier)
// 自定義設定
self.label = "Custom"
self.toolTip = "Custom Tool"
self.image = NSImage(named: NSImage.infoTemplateName)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
動態更新工具欄項
可以透過設定工具欄項的 minSize
和 maxSize
以及使用 validateToolbarItem
方法來動態更新工具欄項。
Objective-C
- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem {
if ([toolbarItem.itemIdentifier isEqualToString:@"FirstItem"]) {
// 根據條件禁用或啟用工具欄項
return YES;
}
return YES;
}
// 更新工具欄項的大小
- (void)updateToolbarItemsSize {
NSToolbarItem *firstItem = [self.toolbar.items firstObject];
[firstItem setMinSize:NSMakeSize(30, 30)];
[firstItem setMaxSize:NSMakeSize(50, 50)];
}
Swift
func validateToolbarItem(_ item: NSToolbarItem) -> Bool {
if item.itemIdentifier.rawValue == "FirstItem" {
// 根據條件禁用或啟用工具欄項
return true
}
return true
}
// 更新工具欄項的大小
func updateToolbarItemsSize() {
if let firstItem = toolbar.items.first {
firstItem.minSize = NSSize(width: 30, height: 30)
firstItem.maxSize = NSSize(width: 50, height: 50)
}
}
隱藏和顯示工具欄
可以透過 setVisible:
方法控制工具欄的顯示和隱藏。
Objective-C
// 隱藏工具欄
[self.window.toolbar setVisible:NO];
// 顯示工具欄
[self.window.toolbar setVisible:YES];
Swift
// 隱藏工具欄
self.window?.toolbar?.isVisible = false
// 顯示工具欄
self.window?.toolbar?.isVisible = true
高階用法
自定義工具欄項檢視
可以自定義工具欄項的檢視,比如將 NSButton 作為工具欄項。
Objective-C
- (NSToolbarItem *)createCustomViewToolbarItemWithIdentifier:(NSString *)identifier label:(NSString *)label action:(SEL)action {
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:identifier];
item.label = label;
item.view = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 30)];
NSButton *button = (NSButton *)item.view;
[button setTitle:label];
[button setTarget:self];
[button setAction:action];
return item;
}
Swift
func createCustomViewToolbarItem(identifier: NSToolbarItem.Identifier, label: String, action: Selector) -> NSToolbarItem {
let item = NSToolbarItem(itemIdentifier: identifier)
item.label = label
let button = NSButton(frame: NSRect(x: 0, y: 0, width: 100, height: 30))
button.title = label
button.target = self
button.action = action
item.view = button
return item
}
動態新增和移除工具欄項
Objective-C
// 動態新增工具欄項
- (void)addToolbarItemWithIdentifier:(NSString *)identifier {
NSToolbarItem *newItem = [self toolbar:nil itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
[self.toolbar insertItemWithItemIdentifier:identifier atIndex:self.toolbar.items.count];
}
// 動態移除工具欄項
- (void)removeToolbarItemWithIdentifier:(NSString *)identifier {
for (NSToolbarItem *item in self.toolbar.items) {
if ([item.itemIdentifier isEqualToString:identifier]) {
[self.toolbar removeItemAtIndex:[self.toolbar.items indexOfObject:item]];
break;
}
}
}
Swift
// 動態新增工具欄項
func addToolbarItem(identifier: NSToolbarItem.Identifier) {
if let newItem = self.toolbar(nil, itemForItemIdentifier: identifier, willBeInsertedIntoToolbar: true) {
toolbar.insertItem(withItemIdentifier: identifier, at: toolbar.items.count)
}
}
// 動態移除工具欄項
func removeToolbarItem(identifier: NSToolbarItem.Identifier) {
for (item in toolbar.items) {
if item.itemIdentifier == identifier {
if let index = toolbar.items.firstIndex(of: item) {
toolbar.removeItem(at: index)
break
}
}
}
}
工具欄定製皮膚
macOS 提供了工具欄定製功能,使用者可以透過它自行選擇工具欄中的項。
Objective-C
// 允許工具欄定製
[toolbar setAllowsUserCustomization:YES];
// 實現代理方法,返回使用者定製時可以看到的項
- (NSArray<NSString *> *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
return @[@"FirstItem", NSToolbarFlexibleSpaceItemIdentifier, @"SecondItem"];
}
- (NSArray<NSString *> *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
return @[@"FirstItem", NSToolbarFlexibleSpaceItemIdentifier, @"SecondItem", @"CustomItem"];
}
Swift
// 允許工具欄定製
toolbar.allowsUserCustomization = true
// 實現代理方法,返回使用者定製時可以看到的項
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [.init("FirstItem"), .flexibleSpace, .init("SecondItem")]
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [.init("FirstItem"), .flexibleSpace, .init("SecondItem"), .init("CustomItem")]
}
封裝工具類
為了更方便地使用 NSToolbar
,可以封裝一個工具類,提供常見功能的高層介面。
Objective-C
#import <Cocoa/Cocoa.h>
@interface NSToolbarHelper : NSObject
+ (NSToolbar *)createToolbarWithIdentifier:(NSString *)identifier delegate:(id<NSToolbarDelegate>)delegate;
+ (NSToolbarItem *)createToolbarItemWithIdentifier:(NSString *)identifier label:(NSString *)label action:(SEL)action target:(id)target image:(NSImage *)image;
@end
@implementation NSToolbarHelper
+ (NSToolbar *)createToolbarWithIdentifier:(NSString *)identifier delegate:(id<NSToolbarDelegate>)delegate {
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:identifier];
[toolbar setDelegate:delegate];
[toolbar setAllowsUserCustomization:YES];
return toolbar;
}
+ (NSToolbarItem *)createToolbarItemWithIdentifier:(NSString *)identifier label:(NSString *)label action:(SEL)action target:(id)target image:(NSImage *)image {
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:identifier];
item.label = label;
item.toolTip = label;
item.image = image;
item.action = action;
item.target = target;
return item;
}
@end
Swift
import Cocoa
class NSToolbarHelper {
// 建立 NSToolbar 並設定代理
static func createToolbar(identifier: String, delegate: NSToolbarDelegate) -> NSToolbar {
let toolbar = NSToolbar(identifier: NSToolbar.Identifier(identifier))
toolbar.delegate = delegate
toolbar.allowsUserCustomization = true
return toolbar
}
// 建立 NSToolbarItem
static func createToolbarItem(identifier: String, label: String, action: Selector, target: AnyObject, image: NSImage) -> NSToolbarItem {
let item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(identifier))
item.label = label
item.toolTip = label
item.image = image
item.action = action
item.target = target
return item
}
}
使用示例
Objective-C
// 建立 NSToolbar
NSToolbar *toolbar = [NSToolbarHelper createToolbarWithIdentifier:@"MainToolbar" delegate:self];
[self.window setToolbar:toolbar];
// 建立並新增工具欄項
NSToolbarItem *firstItem = [NSToolbarHelper createToolbarItemWithIdentifier:@"FirstItem" label:@"First" action:@selector(handleToolbarAction:) target:self image:[NSImage imageNamed:NSImageNameAddTemplate]];
[toolbar insertItemWithItemIdentifier:@"FirstItem" atIndex:0];
NSToolbarItem *secondItem = [NSToolbarHelper createToolbarItemWithIdentifier:@"SecondItem" label:@"Second" action:@selector(handleToolbarAction:) target:self image:[NSImage imageNamed:NSImageNameRemoveTemplate]];
[toolbar insertItemWithItemIdentifier:@"SecondItem" atIndex:1];
Swift
// 建立 NSToolbar
let toolbar = NSToolbarHelper.createToolbar(identifier: "MainToolbar", delegate: self)
self.window?.toolbar = toolbar
// 建立並新增工具欄項
let firstItem = NSToolbarHelper.createToolbarItem(identifier: "FirstItem", label: "First", action: #selector(handleToolbarAction(_:)), target: self, image: NSImage(named: NSImage.addTemplateName)!)
toolbar.insertItem(withItemIdentifier: NSToolbarItem.Identifier("FirstItem"), at: 0)
let secondItem = NSToolbarHelper.createToolbarItem(identifier: "SecondItem", label: "Second", action: #selector(handleToolbarAction(_:)), target: self, image: NSImage(named: NSImage.removeTemplateName)!)
toolbar.insertItem(withItemIdentifier: NSToolbarItem.Identifier("SecondItem"), at: 1)
總結
透過了解 NSToolbar
的基本使用、建立工具欄項、響應工具欄項選擇、自定義工具欄項、動態更新工具欄項、隱藏和顯示工具欄以及工具欄定製皮膚等高階用法,並封裝工具類,你將能夠更高效地使用 NSToolbar
建立複雜的工具欄系統。在實際應用中,合理使用這些技巧可以顯著提升使用者介面的靈活性和使用者體驗。希望本文對你有所幫助,