Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 如何绘制自己的NSTabView选项卡?_Cocoa_User Interface_Nstabview - Fatal编程技术网

Cocoa 如何绘制自己的NSTabView选项卡?

Cocoa 如何绘制自己的NSTabView选项卡?,cocoa,user-interface,nstabview,Cocoa,User Interface,Nstabview,我想为NSTabViewItems绘制我自己的选项卡。我的标签应该看起来不同,从左上角开始,而不是居中 如何才能做到这一点?NSTabView不是Cocoa中最可自定义的类,但可以对其进行子类化并绘制自己的图形。除了维护选项卡视图项的集合外,您不会使用超类中的很多功能,最终将实现许多NSView和NSResponder方法,以使绘图和事件处理正常工作 最好先看看免费或开源的tab bar控件,我以前使用过,这比实现我自己的tab view子类(它正在替换)容易得多。我最近做了一些我正在做的事情

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


如何才能做到这一点?

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


最好先看看免费或开源的tab bar控件,我以前使用过,这比实现我自己的tab view子类(它正在替换)容易得多。

我最近做了一些我正在做的事情

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


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

我对此非常感兴趣—并发布了—因为PSMTabBarControl现在已经过时,也发布了

可以将NSTabView的样式设置为TABLES,然后使用一个NSSECTIONEDCONTROL来控制它子类NSSegmentedCell以覆盖样式和行为。要了解如何做到这一点,请查看这个模拟Xcode 4样式选项卡的项目:。

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

@property NSInteger selectedTabIndex;
然后,在IB绑定检查器中,将
NSTabView
NSSegmentedCell
的选定索引绑定到相同的
selectedTabIndex
属性


这就是你需要做的!您不需要初始化属性,除非您希望默认的选定选项卡索引不是零。您可以保留这些选项卡,也可以使
NSTabView
表可用。无论哪个控件更改选择,控件都将保持同步。

绘制选项卡的可能方法之一是使用NSCollectionView。以下是Swift 4示例:

TabViewStackController
包含
TabViewStackController
预先配置的样式
。未指定
和自定义
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)
      }
   }
}
TabViewController
预先配置了样式
。未指定

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)
      }
   }
}
下面是它的样子:

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)
      }
   }
}
class TabBarCollectionView: CollectionView {

   override func setupUI() {
      isSelectable = true
      allowsMultipleSelection = false
      allowsEmptySelection = false
      backgroundView = View(backgroundColor: .magenta)
      backgroundColors = [.clear]
   }
}

class TabBarScrollView: ScrollView {

   override func setupUI() {
      borderType = .noBorder
      backgroundColor = .clear
      drawsBackground = false

      horizontalScrollElasticity = .none
      verticalScrollElasticity = .none

      automaticallyAdjustsContentInsets = false
      horizontalScroller = InvisibleScroller()
   }
}

// Disabling scroll view indicators.
// See: https://stackoverflow.com/questions/9364953/hide-scrollers-while-leaving-scrolling-itself-enabled-in-nsscrollview
private class InvisibleScroller: Scroller {

   override class var isCompatibleWithOverlayScrollers: Bool {
      return true
   }

   override class func scrollerWidth(for controlSize: NSControl.ControlSize, scrollerStyle: NSScroller.Style) -> CGFloat {
      return CGFloat.leastNormalMagnitude // Dimension of scroller is equal to `FLT_MIN`
   }

   override func setupUI() {
      // Below assignments not really needed, but why not.
      scrollerStyle = .overlay
      alphaValue = 0
   }
}

class TabBarTabViewItem: CollectionViewItem {

   private lazy var titleLabel = Label().autolayoutView()

   override var isSelected: Bool {
      didSet {
         if isSelected {
            titleLabel.font = Font.semibold(size: 10)
            contentView.backgroundColor = .red
         } else {
            titleLabel.font = Font.regular(size: 10.2)
            contentView.backgroundColor = .blue
         }
      }
   }

   override func setupUI() {
      view.addSubviews(titleLabel)
      view.wantsLayer = true
      titleLabel.maximumNumberOfLines = 1
   }

   override func setupDefaults() {
      isSelected = false
   }

   func configure(title: String) {
      titleLabel.text = title
      titleLabel.textColor = .white
      titleLabel.alignment = .center
   }

   override func setupLayout() {
      LayoutConstraint.withFormat("|-[*]-|", titleLabel).activate()
      LayoutConstraint.withFormat("V:|-(>=4)-[*]", titleLabel).activate()
      LayoutConstraint.centerY(titleLabel).activate()
   }
}

class TabContentController: ViewController {

   let content: String
   private lazy var titleLabel = Label().autolayoutView()

   init(content: String) {
      self.content = content
      super.init()
   }

   required init?(coder: NSCoder) {
      fatalError()
   }

   override func setupUI() {
      contentView.addSubview(titleLabel)
      titleLabel.text = content
      contentView.backgroundColor = .green
   }

   override func setupLayout() {
      LayoutConstraint.centerXY(titleLabel).activate()
   }
}