Mac開發基礎21-NSSplitView
NSSplitView 是 macOS 應用中的一個重要控件,允許用戶調整窗口中的各個子視圖大小。它通常用于創建可調整大小的面板布局,例如側邊欄和主內容區域。在本指南中,我們將詳細介紹 NSSplitView 的常見 API 和基礎技巧,并深入探討相關知識。
基本使用
創建和初始化
Objective-C
#import <Cocoa/Cocoa.h>
// 創建一個 NSSplitView 實例
NSSplitView *splitView = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 600, 400)];
// 設置 SplitView 為垂直分隔
[splitView setVertical:YES];
// 添加分配兩邊的子視圖
NSView *leftView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 300, 400)];
[leftView setWantsLayer:YES]; // 啟用 layer 支持(用于視圖的主要特性設置)
[leftView.layer setBackgroundColor:[NSColor lightGrayColor].CGColor]; // 設置背景顏色
NSView *rightView = [[NSView alloc] initWithFrame:NSMakeRect(300, 0, 300, 400)];
[rightView setWantsLayer:YES]; // 啟用 layer 支持
[rightView.layer setBackgroundColor:[NSColor blueColor].CGColor]; // 設置背景顏色
// 將子視圖添加到 SplitView
[splitView addSubview:leftView];
[splitView addSubview:rightView];
Swift
import Cocoa
// 創建一個 NSSplitView 實例
let splitView = NSSplitView(frame: NSRect(x: 0, y: 0, width: 600, height: 400))
// 設置 SplitView 為垂直分隔
splitView.isVertical = true
// 添加分配兩邊的子視圖
let leftView = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 400))
leftView.wantsLayer = true // 啟用 layer 支持(用于視圖的主要特性設置)
leftView.layer?.backgroundColor = NSColor.lightGray.cgColor // 設置背景顏色
let rightView = NSView(frame: NSRect(x: 300, y: 0, width: 300, height: 400))
rightView.wantsLayer = true // 啟用 layer 支持
rightView.layer?.backgroundColor = NSColor.blue.cgColor // 設置背景顏色
// 將子視圖添加到 SplitView
splitView.addSubview(leftView)
splitView.addSubview(rightView)
數據源和委托
使用 NSSplitView 時通常需要設置代理以處理各種事件。
Objective-C
// 設置代理
[splitView setDelegate:self];
// 實現代理方法,控制分隔條的位置和行為
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
return proposedMinimumPosition + 50; // 最小分隔條位置
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
return proposedMaximumPosition - 50; // 最大分隔條位置
}
- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view {
return YES; // 控制是否允許調整子視圖大小
}
Swift
// 設置代理
splitView.delegate = self
// 實現代理方法,控制分隔條的位置和行為
func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
return proposedMinimumPosition + 50 // 最小分隔條位置
}
func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
return proposedMaximumPosition - 50 // 最大分隔條位置
}
func splitView(_ splitView: NSSplitView, shouldAdjustSizeOfSubview view: NSView) -> Bool {
return true // 控制是否允許調整子視圖大小
}
使用自動布局
NSSplitView 支持自動布局,這使得調整窗口大小時能更好地適應變化。
Objective-C
// 使用自動布局進行初始化
NSView *leftView = [[NSView alloc] init];
NSView *rightView = [[NSView alloc] init];
[leftView setTranslatesAutoresizingMaskIntoConstraints:NO]; // 禁用自動轉換約束
[rightView setTranslatesAutoresizingMaskIntoConstraints:NO];
[splitView addSubview:leftView];
[splitView addSubview:rightView];
// 添加約束
[NSLayoutConstraint activateConstraints:@[
[leftView.leadingAnchor constraintEqualToAnchor:splitView.leadingAnchor],
[leftView.topAnchor constraintEqualToAnchor:splitView.topAnchor],
[leftView.bottomAnchor constraintEqualToAnchor:splitView.bottomAnchor],
[leftView.widthAnchor constraintEqualToAnchor:splitView.widthAnchor multiplier:0.5],
[rightView.trailingAnchor constraintEqualToAnchor:splitView.trailingAnchor],
[rightView.topAnchor constraintEqualToAnchor:splitView.topAnchor],
[rightView.bottomAnchor constraintEqualToAnchor:splitView.bottomAnchor],
[rightView.widthAnchor constraintEqualToAnchor:splitView.widthAnchor multiplier:0.5],
]];
Swift
// 使用自動布局進行初始化
let leftView = NSView()
let rightView = NSView()
leftView.translatesAutoresizingMaskIntoConstraints = false // 禁用自動轉換約束
rightView.translatesAutoresizingMaskIntoConstraints = false
splitView.addSubview(leftView)
splitView.addSubview(rightView)
// 添加約束
NSLayoutConstraint.activate([
leftView.leadingAnchor.constraint(equalTo: splitView.leadingAnchor),
leftView.topAnchor.constraint(equalTo: splitView.topAnchor),
leftView.bottomAnchor.constraint(equalTo: splitView.bottomAnchor),
leftView.widthAnchor.constraint(equalTo: splitView.widthAnchor, multiplier: 0.5),
rightView.trailingAnchor.constraint(equalTo: splitView.trailingAnchor),
rightView.topAnchor.constraint(equalTo: splitView.topAnchor),
rightView.bottomAnchor.constraint(equalTo: splitView.bottomAnchor),
rightView.widthAnchor.constraint(equalTo: splitView.widthAnchor, multiplier: 0.5),
])
高級用法
動態增減子視圖
Objective-C
添加子視圖
NSView *newView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 300, 400)];
[newView setWantsLayer:YES];
[newView.layer setBackgroundColor:[NSColor greenColor].CGColor];
// 動態添加到 SplitView
[splitView addSubview:newView positioned:NSWindowAbove relativeTo:nil];
[splitView adjustSubviews]; // 調整子視圖
移除子視圖
NSView *viewToRemove = [splitView.subviews lastObject];
[splitView removeArrangedSubview:viewToRemove];
[viewToRemove removeFromSuperview];
[splitView adjustSubviews]; // 調整子視圖
Swift
添加子視圖
let newView = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 400))
newView.wantsLayer = true
newView.layer?.backgroundColor = NSColor.green.cgColor
// 動態添加到 SplitView
splitView.addSubview(newView, positioned: .above, relativeTo: nil)
splitView.adjustSubviews() // 調整子視圖
移除子視圖
if let viewToRemove = splitView.subviews.last {
splitView.removeArrangedSubview(viewToRemove)
viewToRemove.removeFromSuperview()
splitView.adjustSubviews() // 調整子視圖
}
自定義分隔條
Objective-C
創建自定義分隔條視圖:
@interface CustomDividerView : NSView
@end
@implementation CustomDividerView
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
self.wantsLayer = YES;
self.layer.backgroundColor = [NSColor darkGrayColor].CGColor;
}
return self;
}
@end
在 NSSplitView 代理方法中使用自定義分隔條:
- (NSView *)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex {
NSView *dividerView = [[CustomDividerView alloc] initWithFrame:NSMakeRect(0, 0, splitView.dividerThickness, 100)];
[splitView addSubview:dividerView];
return dividerView;
}
Swift
創建自定義分隔條視圖:
class CustomDividerView: NSView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.wantsLayer = true
self.layer?.backgroundColor = NSColor.darkGray.cgColor
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
在 NSSplitView 代理方法中使用自定義分隔條:
func splitView(_ splitView: NSSplitView, additionalEffectiveRectOfDividerAt dividerIndex: Int) -> NSRect {
let dividerView = CustomDividerView(frame: NSRect(x: 0, y: 0, width: splitView.dividerThickness, height: 100))
splitView.addSubview(dividerView)
return dividerView.frame
}
用于實際應用
示例代碼
Objective-C
#import <Cocoa/Cocoa.h>
#import "CustomDividerView.h"
@interface AppDelegate : NSObject <NSApplicationDelegate, NSSplitViewDelegate>
@property (strong) NSWindow *window;
@property (strong) NSSplitView *splitView;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:NO];
[_window setTitle:@"NSSplitView Example"];
_splitView = [[NSSplitView alloc] initWithFrame:_window.contentView.bounds];
[_splitView setVertical:YES];
[_splitView setDelegate:self];
NSView *leftView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 300, 600)];
[leftView setWantsLayer:YES];
[leftView.layer setBackgroundColor:[NSColor lightGrayColor].CGColor];
NSView *rightView = [[NSView alloc] initWithFrame:NSMakeRect(300, 0, 500, 600)];
[rightView setWantsLayer:YES];
[rightView.layer setBackgroundColor:[NSColor blueColor].CGColor];
[_splitView addSubview:leftView];
[_splitView addSubview:rightView];
[_window.contentView addSubview:_splitView];
[_window makeKeyAndOrderFront:nil];
}
// NSSplitViewDelegate 方法實現
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
return proposedMinimumPosition + 100;
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
return proposedMaximumPosition - 100;
}
- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view {
return YES;
}
- (NSView *)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex {
NSView *dividerView = [[CustomDividerView alloc] initWithFrame:NSMakeRect(0, 0, splitView.dividerThickness, 600)];
[splitView addSubview:dividerView];
return dividerView;
}
@end
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}
Swift
import Cocoa
@main
class AppDelegate: NSObject, NSApplicationDelegate, NSSplitViewDelegate {
var window: NSWindow!
var splitView: NSSplitView!
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSWindow(contentRect: NSMakeRect(0, 0, 800, 600),
styleMask: [.titled, .closable, .resizable],
backing: .buffered,
defer: false)
window.title = "NSSplitView Example"
splitView = NSSplitView(frame: window.contentView!.bounds)
splitView.isVertical = true
splitView.delegate = self
let leftView = NSView(frame: NSMakeRect(0, 0, 300, 600))
leftView.wantsLayer = true
leftView.layer?.backgroundColor = NSColor.lightGray.cgColor
let rightView = NSView(frame: NSMakeRect(300, 0, 500, 600))
rightView.wantsLayer = true
rightView.layer?.backgroundColor = NSColor.blue.cgColor
splitView.addSubview(leftView)
splitView.addSubview(rightView)
window.contentView?.addSubview(splitView)
window.makeKeyAndOrderFront(nil)
}
// NSSplitViewDelegate 方法實現
func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
return proposedMinimumPosition + 100
}
func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
return proposedMaximumPosition - 100
}
func splitView(_ splitView: NSSplitView, shouldAdjustSizeOfSubview view: NSView) -> Bool {
return true
}
func splitView(_ splitView: NSSplitView, additionalEffectiveRectOfDividerAt dividerIndex: Int) -> NSRect {
let dividerView = CustomDividerView(frame: NSRect(x: 0, y: 0, width: splitView.dividerThickness, height: 600))
splitView.addSubview(dividerView)
return dividerView.frame
}
}
class CustomDividerView: NSView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
wantsLayer = true
layer?.backgroundColor = NSColor.darkGray.cgColor
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
總結
通過了解 NSSplitView 的基本使用、委托方法、動態增減子視圖、自定義分隔條等高級用法,你將能夠更有效地使用 NSSplitView 創建可調整大小的復雜布局。在實際應用中,合理使用這些技巧可以顯著提升用戶界面的靈活性和用戶體驗。
將來的你會感謝今天如此努力的你!
版權聲明:本文為博主原創文章,未經博主允許不得轉載。

浙公網安備 33010602011771號