【问题标题】:Positioning inspector bar for NSTextViewNSTextView 的定位检查器栏
【发布时间】:2012-08-02 20:36:54
【问题描述】:

为文本视图启用“检查器栏”很容易,因此屏幕顶部会出现一个带有各种格式按钮的栏。 (虽然在我学会确保我在滚动视图中选择文本视图,而不是滚动视图本身之前,我有些困惑)。我可以以编程方式使用 [textView setUsesInspectorBar:YES] 或转到 Attributes Inspector 并检查“Uses”部分中的“Inspector Bar”框。

我的问题是,如何进一步控制检查栏?我无法在 XCode 文档或在线中找到有关它的信息。我希望能够将其放置在屏幕上的不同位置。能够选择栏中的特定控件也很棒。

【问题讨论】:

    标签: objective-c xcode cocoa


    【解决方案1】:

    答案是,您不应该进一步控制检查栏。文档中什么都没有,因为,好吧,什么都没有。苹果的说法,用它还是不用它。

    然而,如果你深入研究一下,你会发现inspector bar是一个非常有趣的控件。它不显示为文本视图的一部分,而是(私下)嵌入在“窗口视图”本身中。当我说“窗口视图”时,我指的是内容视图的超级视图。

    如果你列出那个“窗口视图”的子视图:

    NSLog(@"%@", [self.testTextView.window.contentView superview].subviews);
    

    你最终得到:

    2012-08-02 15:59:30.145 Example[16702:303] (
        "<_NSThemeCloseWidget: 0x100523dc0>", // the close button
        "<_NSThemeWidget: 0x100525ce0>", // the minimize button?
        "<_NSThemeWidget: 0x100524e90>", // the maximize button?
        "<NSView: 0x100512ad0>", // the content view
        "<__NSInspectorBarView: 0x100529d50>", // the inspector view
        "(<NSToolbarView: 0x10054e650>: FD2E0533-AB18-4E7E-905A-AC816CB80A26)" // the toolbar
    )
    

    如您所见,AppKit 将检查器栏置于与其他顶级窗口控件相同的级别。现在这进入了私有 API 的领域,但简单地修补“窗口视图”不应该让任何应用程序被拒绝。


    您可以尝试从此处获取对__NSInspectorBarView 的引用。似乎它总是紧跟在内容视图之后的子视图,所以这样的事情可能会起作用:

    NSArray *topLevelViews = [self.testTextView.window.contentView superview].subviews;
    NSUInteger indexOfContentView = [topLevelViews indexOfObject:self.testTextView.window.contentView];
    if (indexOfContentView + 1 < topLevelViews.count) {
        NSView *inspectorBar = [topLevelViews objectAtIndex:indexOfContentView + 1];
        NSLog(@"%@", inspectorBar);
    }
    NSLog(@"%@", topLevelViews);
    

    由于如果 Apple 更改顶级视图的顺序,这会立即中断,因此对于生产应用程序可能不是一个好主意。另一个想法是:

    NSView *inspectorBarView = nil;
    for (NSView *topLevelView in topLevelViews) {
        if ([topLevelView isKindOfClass:NSClassFromString(@"__NSInspectorBarView")]) {
            inspectorBarView = topLevelView;
        }
    }
    NSLog(@"%@", inspectorBarView);
    

    我不知道NSClassFromString() 的使用是否会通过 App Store 审核指南,但是,因为它再次依赖于私有 API。


    话虽如此,一旦您获得对检查栏视图的引用,事情仍然不能很好地工作。您可以尝试将其重新定位在底部:

    if (inspectorBarView) {
        NSRect newFrame = inspectorBarView.frame;
        newFrame.origin = NSZeroPoint;
        [inspectorBarView setAutoresizingMask:NSViewMaxYMargin | NSViewMaxXMargin];
        [inspectorBarView setFrame:newFrame];
    }
    

    但你最终会得到一个错误绘制的工具栏,因此需要更多的工作:

    我的想法是尝试将内容视图的高度向上移动以覆盖灰色的剩余区域(每次调整窗口大小时都必须这样做,也许修补自动调整大小的蒙版可能会更容易)和自定义为底部的检查栏绘制背景。

    编辑

    哦,您也应该为此提交功能请求。 bugreport.apple.com

    【讨论】:

      【解决方案2】:

      这已经晚了四年,但我觉得互联网上的某个人将来可能会从中受益。我花了太长时间试图弄清楚这一点。

      正如其他人所指出的,检查栏类似乎是一个私有类(__NSInspectorBarView)。因此,可能不建议修改。

      尽管如此!好奇的人必须知道。在本文发布时(2016 年 4 月),检查器栏已插入到窗口的附件栏中。您可以使用 NSWindow 中名为 titlebarAccessoryViewControllers[] 的数组属性获取 OS X 10.10 的附件视图列表。

      这里有一些 Swift 2.0 代码可以做到这一点,假设您事先没有在窗口中插入任何其他辅助视图。

      if window.titlebarAccessoryViewControllers.count > 0 {
              let textViewInspectorBar = self.titlebarAccessoryViewControllers[0].view
              let inspectorBarHeight: CGFloat = textViewInspectorBar!.frame.height // 26.0 pt
          }
      

      值得注意的是,附件视图在全屏模式应用中的处理方式不同:https://developer.apple.com/library/mac/documentation/General/Conceptual/MOSXAppProgrammingGuide/FullScreenApp/FullScreenApp.html

      我个人不会尝试移动辅助视图,因为它们是设计用于保留在工具栏中的特殊类型的视图(如果我完全理解我所阅读的内容)。

      NSTitlebarAccessoryViewController 参考: https://developer.apple.com/library/mac/documentation/AppKit/Reference/NSTitlebarAccessoryViewController_Class/

      【讨论】:

      • 为其他程序员提供有用的信息永远不会太晚! :)
      【解决方案3】:

      又过了 3 年,但我怀疑有些人会觉得这很有用。我的具体问题是让一个窗口完全被 tabView 填满 - 非常适合设置各种用户默认值。这些标签页中只有一个有几个文本视图,我希望检查器栏可见。切换到该页面使检查器栏出现,并将整个区域向下推,破坏了我精心设计的布局。离开页面并没有再次隐藏它。

      显而易见的事情是让检查栏只出现在相关的标签页上。掌握了它(“站在巨人的肩膀上”——感谢巨人 Vervious),在视图层次结构中重新定位它相对容易。您仍然存在将内容向下推的空工具栏的空间问题。当检查栏第一次出现时,窗口的视图层次结构发生了根本性的变化,我放弃了尝试用它做任何事情。 我的解决方案是增加内容视图的高度。 (为什么高度而不是起源我不能说。)

      func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {
        if let inspectorBar = window!.titlebarAccessoryViewControllers.first(where:
          {$0.view.className == "__NSInspectorBarView"} )?.view {
      
          // move content view back to where it should be
          var sz = window!.contentView!.frame.size
          sz.height = window!.frame.size.height - 21
          window!.contentView?.setFrameSize(sz)
      
          // put the inspector where we want it
          inspectorBar.removeFromSuperview()
          let y = textPage.frame.size.height - inspectorBar.frame.size.height - 10
          inspectorBar.setFrameOrigin(NSPoint(x: 0, y: y))
          textPage.subviews.insert(inspectorBar, at: 0)
        }
      }
      

      代码属于NSTabViewDelegate,我使我的窗口控制器符合它,记住将tabView的委托设置为xib中的文件所有者,并且在选择新选项卡时调用。 textPage 是相关 tabViewItem 内的视图。

      有一些通过反复试验发现的任意常数。该功能只需要运行一次。重复调用是无害的,但您可以设置一个标志,以便从后续调用中提前返回。

      【讨论】:

        【解决方案4】:

        你不能做任何事情来定位这个东西。 显然,@Vervious 指出的损坏是真实的,但只有在你没有 NSToolBar 的情况下。 你看,这个inspectorBar 很遗憾是一个主要是私有的并且大部分(公开)无证但很棒的工具。而且它非常适合在具有可见 NSToolBar 的窗口中使用...看图。

        将工具栏添加到视图后

        仍然有一个工具栏但被隐藏了,检查栏很酷 (如通过视图菜单或它调用的方法,即 toggleToolBarShown: 并且是 NSResponder 友好消息)

        所以很明显,不,您对此无能为力。它的设计记录很差。它可以作为 NSToolbar 所在位置下的伪附件视图栏(这也是不可调整的)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多