如何绘制自己的NSTabView标签?

时间:2009-06-06 11:15:12

标签: cocoa user-interface nstabview

我想为NSTabViewItem绘制自己的标签。我的标签应该看起来不同,从左上角开始,而不是居中。

我该怎么做?

6 个答案:

答案 0 :(得分:4)

可以将NSTabView的样式设置为Tabless,然后使用NSSegmentedControl控制它,该NSSegmentedControl将NSSegmentedCell子类化以覆盖样式和行为。有关如何执行此操作的想法,请查看模拟Xcode 4样式选项卡的此项目:https://github.com/aaroncrespo/WILLTabView/

答案 1 :(得分:3)

NSTabView不是Cocoa中最可自定义的类,但可以将其子类化并自己绘制。除了维护一组选项卡视图项之外,您不会使用超类中的太多功能,并且您最终将实现许多NSView和NSResponder方法以使绘图和事件处理正常工作。

最好首先查看一个免费或开源标签栏控件,我过去使用过PSMTabBarControl,这比实现我自己的标签视图子类要容易得多(这是它取代了什么。

答案 2 :(得分:3)

我最近为我正在做的事情做了这件事。

我结束了使用tabless标签视图,然后在另一个视图中自己绘制标签。我希望我的标签成为窗口底部状态栏的一部分。

你显然需要支持鼠标点击这很容易,但你应该确保你的键盘支持也能正常工作,这有点棘手:你需要运行计时器来切换标签,一半后没有键盘访问一秒钟(看看OS X的方式)。可访问性是你应该考虑的另一件事,但你可能会发现它只是工作 - 我还没有在我的代码中检查它。

答案 3 :(得分:3)

绘制标签的一种可能方法是使用NSCollectionView。这是Swift 4的例子:

TabViewStackController包含预先配置了样式TabViewController和自定义.unspecified的{​​{1}}。

TabBarView

班级class TabViewStackController: ViewController { private lazy var tabBarView = TabBarView().autolayoutView() private lazy var containerView = View().autolayoutView() private lazy var tabViewController = TabViewController() private let tabs: [String] = (0 ..< 14).map { "TabItem # \($0)" } override func setupUI() { view.addSubviews(tabBarView, containerView) embedChildViewController(tabViewController, container: containerView) } override func setupLayout() { LayoutConstraint.withFormat("|-[*]-|", forEveryViewIn: containerView, tabBarView).activate() LayoutConstraint.withFormat("V:|-[*]-[*]-|", tabBarView, containerView).activate() } override func setupHandlers() { tabBarView.eventHandler = { [weak self] in switch $0 { case .select(let item): self?.tabViewController.process(item: item) } } } override func setupDefaults() { tabBarView.tabs = tabs if let item = tabs.first { tabBarView.select(item: item) tabViewController.process(item: item) } } } 包含代表标签的TabBarView

CollectionView

class TabBarView: View { public enum Event { case select(String) } public var eventHandler: ((Event) -> Void)? private let cellID = NSUserInterfaceItemIdentifier(rawValue: "cid.tabView") public var tabs: [String] = [] { didSet { collectionView.reloadData() } } private lazy var collectionView = TabBarCollectionView() private let tabBarHeight: CGFloat = 28 private (set) lazy var scrollView = TabBarScrollView(collectionView: collectionView).autolayoutView() override var intrinsicContentSize: NSSize { let size = CGSize(width: NSView.noIntrinsicMetric, height: tabBarHeight) return size } override func setupHandlers() { collectionView.delegate = self } override func setupDataSource() { collectionView.dataSource = self collectionView.register(TabBarTabViewItem.self, forItemWithIdentifier: cellID) } override func setupUI() { addSubviews(scrollView) wantsLayer = true let gridLayout = NSCollectionViewGridLayout() gridLayout.maximumNumberOfRows = 1 gridLayout.minimumItemSize = CGSize(width: 115, height: tabBarHeight) gridLayout.maximumItemSize = gridLayout.minimumItemSize collectionView.collectionViewLayout = gridLayout } override func setupLayout() { LayoutConstraint.withFormat("|[*]|", scrollView).activate() LayoutConstraint.withFormat("V:|[*]|", scrollView).activate() } } extension TabBarView { func select(item: String) { if let index = tabs.index(of: item) { let ip = IndexPath(item: index, section: 0) if collectionView.item(at: ip) != nil { collectionView.selectItems(at: [ip], scrollPosition: []) } } } } extension TabBarView: NSCollectionViewDataSource { func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { return tabs.count } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let tabItem = tabs[indexPath.item] let cell = collectionView.makeItem(withIdentifier: cellID, for: indexPath) if let cell = cell as? TabBarTabViewItem { cell.configure(title: tabItem) } return cell } } extension TabBarView: NSCollectionViewDelegate { func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) { if let first = indexPaths.first { let item = tabs[first.item] eventHandler?(.select(item)) } } } 预先配置了样式TabViewController

.unspecified

其他课程。

class TabViewController: GenericTabViewController<String> {

   override func viewDidLoad() {
      super.viewDidLoad()
      transitionOptions = []
      tabStyle = .unspecified
   }

   func process(item: String) {
      if index(of: item) != nil {
         select(itemIdentifier: item)
      } else {
         let vc = TabContentController(content: item)
         let tabItem = GenericTabViewItem(identifier: item, viewController: vc)
         addTabViewItem(tabItem)
         select(itemIdentifier: item)
      }
   }
}

以下是它的样子:

Result

答案 4 :(得分:1)

我非常坚持这一点 - 并发布了NSTabView with background color - 因为PSMTabBarControl现已过期,也发布了https://github.com/dirkx/CustomizableTabView/blob/master/CustomizableTabView/CustomizableTabView.m

答案 5 :(得分:0)

NSSegmentedCell中使用单独的NSTabView来控制标签选择非常容易。您只需要一个实例变量,它们都可以绑定到文件的所有者或者nib文件中出现的任何其他控制器类。只需在接口声明类中输入类似的东西:

@property NSInteger selectedTabIndex;

然后,在IB Bindings检查器中,将NSTabViewNSSegmentedCell的选定索引绑定到同一selectedTabIndex属性。

这就是你需要做的一切!除非您希望默认选定的选项卡索引不是零,否则您不需要初始化属性。你可以保留标签,也可以制作NSTabView表格,它可以任意方式工作。无论哪个控件改变选择,控件都将保持同步。