macOS子视图区域NSSplitView
macOS子视图区域NSSplitView

macOS子视图区域NSSplitView

NSSplitView 是 macOS AppKit 框架中的一个类,用于将窗口或视图划分为多个可调整大小的子视图区域,比如 Finder 左侧的目录树和右侧的文件列表,或者 Xcode 的侧边栏、代码编辑区和调试面板。

基本用法

1、创建NSSplictView:

let splitView = NSSplitView()

2、设置子视图

let splitView = NSSplitView()
splitView.isVertical = true // true = 左右分栏,false = 上下分栏

// 添加左视图
let leftView = NSView()
leftView.wantsLayer = true
leftView.layer?.backgroundColor = NSColor.red.cgColor

// 添加右视图
let rightView = NSView()
rightView.wantsLayer = true
rightView.layer?.backgroundColor = NSColor.blue.cgColor

splitView.addArrangedSubview(leftView)
splitView.addArrangedSubview(rightView)

水平或垂直划分区域,用户可以拖动中间的分隔条调整每个区域的大小。

常用属性和方法

1、isVertical:是否垂直分割(左右)。

splitView.isVertical = true // true = 左右分栏,false = 上下分栏

2、addArrangedSubview(_:):添加子视图。

splitView.addArrangedSubview(leftView)

3、setPosition(_:ofDividerAt:):设置某个分割条的位置。

DispatchQueue.main.async {
    splitView.setPosition(100, ofDividerAt: 0)
    splitView.adjustSubviews()
}

参数 100:表示第 0 个分割条左(或上)侧的视图宽度或高度

参数 ofDividerAt: 0:第 0 个分隔条(即第一个分栏)

注意,需要延迟设置分割条的位置,让 layout 先完成,否则无法限制分割条宽度或高度。

4、adjustSubviews():强制重新布局。

通常在初始化子视图、调用setPosition(…)后,改变视图大小或更新内容后调用,它会自动依据当前分割条位置重新布局所有 arrangedSubview。

5、dividerThickness:分隔条宽度,只读属性。

let thickness = splitView.dividerThickness

通常是 1 或 2 像素,可用于计算布局偏移或自定义分隔行为时参考。

6、delegate:实现拖动限制或自定义行为。

通过实现 NSSplitViewDelegate 来控制拖动行为,比如:

限制某一栏最小或最大尺寸。

防止某一栏被拖没(宽度为 0)。

只允许某一侧变化,另一侧保持固定大小。

class MySplitDelegate: NSObject, NSSplitViewDelegate {
    func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMin: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return 150 // 限制左侧最小宽度 150pt
    }

    func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMax: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return proposedMax - 150 // 限制右侧最小宽度
    }
}

使用方法:

let splitView = NSSplitView()
splitView.delegate = MySplitDelegate()

使用场景

1、在SwiftUI中实现NSSplitView

import SwiftUI
import AppKit

struct LefttView: View {
    var body: some View {
        VStack {
            Text("左视图")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct RightView: View {
    var body: some View {
        VStack {
            Text("右视图")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(.red.opacity(0.3))
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            MySlider()
        }
        .frame(width: 400,height:300)
    }
}

struct MySlider: NSViewRepresentable {
    // @Binding var value: Double
    func makeCoordinator() -> Coordinator {
            Coordinator()
        }
    func makeNSView(context: Context) -> NSSplitView {
        let splitView = NSSplitView()
        splitView.isVertical = true // true = 左右分栏,false = 上下分栏
        
        // 添加左视图
        let leftView = NSHostingController(rootView: LefttView()).view
        
        // 添加右视图
        let rightView = NSHostingController(rootView: RightView()).view
        
        splitView.addArrangedSubview(leftView)
        splitView.addArrangedSubview(rightView)
        
        DispatchQueue.main.async {
                    splitView.setPosition(100, ofDividerAt: 0)
                    splitView.adjustSubviews()
                }

        splitView.delegate = context.coordinator.delegate
        
        return splitView
    }
    
    func updateNSView(_ nsView: NSSplitView, context: Context) { }
    
    class Coordinator {
            let delegate = MySplitDelegate()
        }
}

class MySplitDelegate: NSObject, NSSplitViewDelegate {
    func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMin: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return 150
    }

    func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMax: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return splitView.bounds.width - 150
    }
}

总结                             

NSSplitView可以灵活划分界面、多区域,支持用户拖动调整大小。

可水平/垂直切割,潜逃使用,拖动行为需手动控制或代理实现。

当有多个NSViewController时,建议使用NSSplitViewController管理,可以自动管理子控制器的生命周期。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注