如何创建类似于 Xcode 属性面板的选项卡式面板

How do I create a tabbed panel similar to the Xcode properties panel

我正在尝试创建一个类似于 Xcode 属性面板的选项卡式面板,但标准选项卡式面板似乎具有不同的外观,无法更改。应使用哪些控件来创建外观相似的选项卡式面板?

编辑: 我没有使用 NSTabViewController - 只有 TabView !!

如果您使用故事板,只需将选项卡视图控制器拖到表面并连接到 window。 然后进入tab view controller的IB设置,把toolbar的样式改成如下图:

然后添加标签并为每个标签添加图像,如下所示:

运行 您的应用并欣赏 XCode 设置视图的外观:

我刚刚使用情节提要和提供的布局创建了一个新项目,并在顶部的视图控制器视图中添加了一个自定义视图。向自定义视图添加按钮,style = square,type = toggle,并使用提供的模板类型图标。将标签分配给按钮 0-4 并将它们放入水平堆栈视图。然后添加了一条水平线和一个容器视图。然后我将一个选项卡视图控制器添加到故事板并将其嵌入到容器视图中。所有按钮都连接到相同的操作。

import Cocoa

class ViewController: NSViewController {

    @IBOutlet var myStackView: NSStackView!

    var oldSelection: Int = 0
    var newSelection: Int = 0

    var buttons: [NSButton]?
    var tabViewDelegate: NSTabViewController?

    @IBAction func selectedButton(_ sender: NSButton) {
        newSelection = sender.tag
        tabViewDelegate?.selectedTabViewItemIndex = newSelection

        buttons![oldSelection].state = .off
        sender.state = .on

        oldSelection = newSelection
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        buttons = (myStackView.arrangedSubviews as! [NSButton])
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        // Once on load
        tabViewDelegate = segue.destinationController as?  NSTabViewController
    }

}

SwiftUI

实施

struct SystemSegmentControl : View {
    
    // MARK: - Internal -

    @Binding var selection : Int
    let systemImages: [String]

    var body : some View {
        HStack(spacing: 5) {
            ForEach (0..<systemImages.count) { i in
                SystemSegmentButton(selection: self.$selection, selectionIndex: i, systemImage: systemImages[i])
              }
        }
    }
}


struct SystemSegmentButton : View {
    
    // MARK: - Internal -

    @Binding var selection : Int
    let selectionIndex: Int
    let systemImage : String

    var body : some View {
        Button(action: { self.selection = self.selectionIndex }) {
            Image(systemName: systemImage)
                .padding(8)
                .foregroundColor(selectionIndex == selection ? .controlAccentColor : .controlColor)
        }
        .buttonStyle(BorderlessButtonStyle())
    }
}

用法

struct SettingsView: View {
    
    // MARK: - Internal -
            
    var body: some View {
        GeometryReader { geometry in
            VStack(spacing: 0) {
                SystemSegmentControl(selection: $selection, systemImages: ["slider.horizontal.3", "eye"])
                Divider()
                switch selection {
                case 0:
                    Text("Tab 1")
                default:
                    Text("Tab 2")
                }
            }
            .frame(width: geometry.size.width, height: geometry.size.height, alignment: .topLeading)
        }
        .frame(width: 250)
    }
    
    // MARK: - Private -
    
    @State private var selection = 0

}

结果