4

enter image description here

I am trying to create a tabbed panel similar to the Xcode properties panel but the standard tabbed panel appears to have a different look and feel with no way to change it. What controls should be used to create a similar looking tabbed panel?

EDIT: I was not using a NSTabViewController - just had the TabView !!

Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76

3 Answers3

5

I just created a new project with storyboard and with the provided layout, added to the View Controllers view a custom view at top. To the custom view added buttons, style = square, type = toggle, and used provided icons of type template. Assigned tag to buttons 0-4 and did put them to a horizontal stack view. Then added a horizontal line and a container view. Then I add a Tab View Controller to the storyboard and embed it to container view. All buttons are connected to same action.

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
    }

}
Peter Ahlberg
  • 1,359
  • 2
  • 24
  • 26
3

If you use storyboards, just drag tab view controller to the surface and connect to the window. Then go to IB settings of tab view controller and change style to toolbar as shown below:

enter image description here

Then add tabs and add image to each tab as shown below:

enter image description here

Run your app and enjoy the look as XCode settings view:

enter image description here

Eugene Mankovski
  • 1,180
  • 10
  • 16
  • OK so this is almost what I want, except I want the tab buttons to appear above the properties panel and not in the apps toolbar. – Duncan Groenewald Nov 23 '16 at 00:57
  • @DuncanGroenewald Unfortunately, if you need any sort of custom behavior, you need to use a different approach. NSTabView with tabless style and bind selected index to a variable in controller. Then create a set of image buttons or other types of buttons and place them in stack view and anchor stack view to the top of tabless NSTabView. Same way as we do stuff in iOS. Then have some selection logic e.t.c. – Eugene Mankovski Nov 23 '16 at 01:14
  • Mmm ok, seems odd they use the Xcode style tabs all over but don't have it as a standard option – Duncan Groenewald Nov 23 '16 at 02:30
  • Yes, if you notice Xcode style tabs are normally a part of toolbar, which is attached to a separate window. Either standalone, modal or sheet style. – Eugene Mankovski Nov 23 '16 at 02:49
3

SwiftUI

Implementation

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

Usage

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

}

Result

enter image description here

Lausbert
  • 1,471
  • 2
  • 17
  • 23