【问题标题】:Change selection color on view-based NSTableView在基于视图的 NSTableView 上更改选择颜色
【发布时间】:2012-03-16 20:35:50
【问题描述】:

OS X 应用程序中的标准突出显示颜色是蓝色。

是否可以将其更改为另一种颜色,例如灰色?

请注意,我使用的是从 OS X 10.7 开始提供的基于视图的新 NSTableView

【问题讨论】:

    标签: objective-c cocoa osx-lion nstableview


    【解决方案1】:

    在 IB 中也找不到这个。上面的答案告诉您在 tableview delegate tableViewSelectionDidChange: 中进行设置,但缺点是您(我)在选择行时仍然会看到短暂的蓝色闪烁。 p>

    我在 datasource 中执行 setEmphasized:NO: tableView:viewForTableColumn:row:

    NSTableRowView *rowView = [tableView rowViewAtRow:row makeIfNecessary:YES];
    [rowView setEmphasized:NO];
    

    因此,在进行任何选择之前应用此设置,并且蓝色永远不会出现。对于这个问题,子类化似乎太过分了。

    EDIT1:如果您在表格中滚动并单击,或者转到另一个应用程序并返回,则蓝色选择会返回,所以我的建议是执行 [rowView setEmphasized:NO]; 委托数据源中的过程。短暂的蓝色闪烁仍然不时发生。 (macOS 10.15.7 Catalina)

    EDIT2:View based NSTableView selection highlighting 建议添加:

    tableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
    

    这似乎完全摆脱了蓝色选择,即使没有摆弄 setEmphasized!

    编辑 3(最终):毕竟,您可以在 IB 中设置它,它是设置“突出显示”,在“样式”下,在复选框“交替行”上方。设置为“无”,等等。

    【讨论】:

      【解决方案2】:

      我已经混合了之前描述的所有方法,得到的代码完全符合我的要求。

      • 选择不会改变内部文本字段的颜色;
      • 行记住一个的选择和颜色;
      • 出现任何奇怪的外边框和其他残留物。

        class AudioCellView: NSTableRowView {
        
            override func draw(_ dirtyRect: NSRect) {
                super.draw(dirtyRect)
                self.wantsLayer = true
                self.layer?.backgroundColor = NSColor.white.cgColor
            }
        
            override var isEmphasized: Bool {
                set {}
                get {
                    return false
                }
            }
        
            override var selectionHighlightStyle: NSTableView.SelectionHighlightStyle {
                set {}
                get {
                    return .regular
                }
            }
        
            override func drawSelection(in dirtyRect: NSRect) {
                if self.selectionHighlightStyle != .none {
                    let selectionRect = NSInsetRect(self.bounds, 2.5, 2.5)
                    NSColor(calibratedWhite: 0.85, alpha: 0.6).setFill()
                    let selectionPath = NSBezierPath.init(rect: selectionRect)
                    selectionPath.fill()
                }
            }
        }
        

      【讨论】:

        【解决方案3】:

        这是 Jean-Pierre 在 Swift3 中的回答:

        func tableViewSelectionDidChange(_ notification: Notification)
            { 
                index = tableView.selectedRow
                let rowView = tableView.rowView(atRow: index, makeIfNecessary: false)
                rowView?.isEmphasized = false
        ...
        

        它有上面列出的两个限制——第一次点击不起作用,第二次点击起作用。并且,还有一种“舞蹈效应”。我不介意第一个,实际上喜欢第二个。

        【讨论】:

          【解决方案4】:

          好的,所以我知道它已经有一个可接受的答案,但是对于像我这样使用NSOutlineView 并拥有.selectionHighlightStyle = .sourceList 的人来说,可以使用此代码将选择设为灰色。此方法在更改选择时不会闪烁,并且在应用最小化时也会保持灰色。

          NSTableView/NSOutlineView 委托:

          func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView?
          {
               let row : CustomRowView = CustomRowView.init()
               row.identifier = "row"
          
               return row
          }
          

          然后用这个创建一个新的CustomRowView.swift 文件:

          class CustomRowView : NSTableRowView
          {
              override var isEmphasized: Bool {
                  get { return self.isEmphasized }
                  set(isEmp) { self.isEmphasized = false }
              }
          }
          

          这将使选择始终保持灰色。

          【讨论】:

          • 这个解决方案显然会导致堆栈溢出。您正在 isEmphasized 属性的设置器中设置 isEmphasized 属性。只需使用 setter 来设置私有变量。通过这个小改动,解决方案效果很好。
          【解决方案5】:

          这是 James Chen 在 Swift 3 中的解决方案。我还添加了委托方法。

          class MyNSTableRowView: NSTableRowView {
          
              override func drawSelection(in dirtyRect: NSRect) {
                  if self.selectionHighlightStyle != .none {
                      let selectionRect = NSInsetRect(self.bounds, 2.5, 2.5)
                      NSColor(calibratedWhite: 0.65, alpha: 1).setStroke()
                      NSColor(calibratedWhite: 0.82, alpha: 1).setFill()
                      let selectionPath = NSBezierPath.init(roundedRect: selectionRect, xRadius: 6, yRadius: 6)
                      selectionPath.fill()
                      selectionPath.stroke()
                  }
              }
          }
          

          NSTableViewDelegate:

          func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
              return MyNSTableRowView()
          }
          

          【讨论】:

            【解决方案6】:

            如前所述,将强调属性设置为 false,但在自定义 NSTableRowView 类中执行此操作以避免副作用(如跳舞颜色效果):

                override func drawRect(dirtyRect: NSRect) {
                   super.drawRect(dirtyRect)
                   self.emphasized = false
            
                }
            

            【讨论】:

              【解决方案7】:

              让-皮埃尔回答的一些修改

              使用以下代码响应NSTableViewDelegate协议tableViewSelectionDidChange:

              获取所选行的 NSTableRowView 并对其调用 setEmphasized 方法。当 setEmphasized 设置为 YES 时,您将获得蓝色突出显示,当您设置为 NO 时,您将获得灰色突出显示。

              -(void)tableViewSelectionDidChange:(NSNotification *)aNotification {
              
               NSInteger selectedRow = [myTableView selectedRow];
               NSTableRowView *myRowView = [myTableView rowViewAtRow:selectedRow makeIfNecessary:NO];
              [myRowView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular];
              [myRowView setEmphasized:NO];
              }
              

              并且要避免蓝色然后灰色设置的跳舞效果

              [_tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
              

              【讨论】:

              • 我可以工作,但我最小化应用程序并再次打开它,它又是蓝色
              【解决方案8】:

              使用 Swift 时,您可以在 10.10 上为基于视图的单元格执行此操作

              继承 NSTableCellView 并实现它:

              //override to change background color on highlight
              override var backgroundStyle:NSBackgroundStyle{
                  //check value when the style was setted
                  didSet{
                      //if it is dark the cell is highlighted -> apply the app color to it
                      if backgroundStyle == .Dark{
                          self.layer!.backgroundColor = yourColor
                      }
                      //else go back to the standard color
                      else{
                          self.layer!.backgroundColor = NSColor.clearColor().CGColor
                      }
                  }
              }
              

              注意NSTableView 高亮样式必须设置为Regular,如果它在SourceList 上会导致一些奇怪的剪辑。

              这不是最干净的解决方案,但它在优胜美地上效果很好

              【讨论】:

              • 它不起作用。 10.10;基于视图的单元格; nstablecellview 子类与您的代码(但我必须使用?而不是!在“层”之后,否则我会崩溃);常规高亮样式。
              • 这有效,除非您的单元格之间有空间。默认高亮颜色显示在单元格背景后面。截图:d.pr/i/QzMu1I(Xcode 8.3.3, Swift 3.1)
              【解决方案9】:
                Use this Notification for NSTableView:
              
                        - (void)tableViewSelectionDidChange:(NSNotification *)notification
                          {
              
                               //You Logic stuff
                           }
              

              【讨论】:

                【解决方案10】:
                - (void)tableViewSelectionDidChange:(NSNotification *)notification
                {
                    [tblCategory enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row){
                        CustomMainCell *cellView = [rowView viewAtColumn:0];
                        if(rowView.selected){
                            cellView.txtFieldTitle.textColor=[NSColor colorWithCalibratedRed:245.0/255.0 green:110.0/255.0 blue:65.0/255.0 alpha:1.0];
                        }else{
                            cellView.txtFieldTitle.textColor=[NSColor whiteColor];
                        }
                    }];
                }
                

                [tblCategory setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];

                【讨论】:

                  【解决方案11】:

                  使用以下代码响应NSTableViewDelegate协议tableViewSelectionDidChange

                  获取所选行的NSTableRowView 并在其上调用方法setEmphasized。 当setEmphasized 设置为 YES 时,您将获得蓝色突出显示,当您设置为 NO 时,您将获得灰色突出显示。

                  -(void)tableViewSelectionDidChange:(NSNotification *)aNotification {
                  
                       NSInteger selectedRow = [myTableView selectedRow];
                       NSTableRowView *myRowView = [myTableView rowViewAtRow:selectedRow makeIfNecessary:NO];
                       [myRowView setEmphasized:NO];
                  }
                  

                  【讨论】:

                  • 谢谢。这真是一个有用的答案。
                  • 这给出了蓝色然后灰色的舞蹈效果......糟糕的用户体验。
                  • 当我们第一次单击该行时,此解决方案不起作用。从第二次点击它就可以工作了。
                  • 如果你在 SelectionIsChanging 方法中使用相同的代码,它也适用于第一次点击
                  • 如果我最小化应用程序并再次打开它仍然显示蓝色
                  【解决方案12】:

                  你必须继承NSTableView,并重写下面的函数来改变交替的颜色。

                  • (void) drawRow: (NSInteger) row clipRect: (NSRect) clipRect

                  • (void) drawBackgroundInClipRect: (NSRect) clipRect**这个改主副色**

                  使用 for 循环并插入此条件 (i % 2 == 0) 来检测奇数行和偶数行。

                  【讨论】:

                  • 澄清一下,这不是问题所问的基于视图的 NSTableviews 的正确答案。您应该只为基于单元格的内容覆盖上述内容。
                  【解决方案13】:

                  由于您使用的是基于视图的 NSTableView,因此您可以继承 NSTableRowView,将其提供给表委托方法 - (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row;,然后在行视图类中自定义您的选择。

                  这是一个例子:

                  - (void)drawSelectionInRect:(NSRect)dirtyRect {
                      if (self.selectionHighlightStyle != NSTableViewSelectionHighlightStyleNone) {
                          NSRect selectionRect = NSInsetRect(self.bounds, 2.5, 2.5);
                          [[NSColor colorWithCalibratedWhite:.65 alpha:1.0] setStroke];
                          [[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill];
                          NSBezierPath *selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:6 yRadius:6];
                          [selectionPath fill];
                          [selectionPath stroke];
                      }
                  }
                  

                  【讨论】:

                  • WWDC 2011 session 120 "View Based NSTableView Basic to Advanced" 给出了类似的例子,也描述了如何根据表格是否为 firstResponder / "active selection" / "emphasized" 来实现不同的颜色。
                  • 似乎如果表视图被声明为 source list drawSelectionInRect: 在 OS X 10.10 Yosemite 上根本没有被调用。只有当一个表被声明为 regular 表时,才会在 Yosemite 上发生这种情况。
                  • 据我所知,这也覆盖了表格“模糊”状态的背景颜色(例如,当您选择一行时,然后在 UI 中的其他位置单击 NSTextField )。此背景颜色保持不变,但文本变暗。如果您使用深色高光颜色,这看起来不太好。知道如何让表格将其默认灰色用于“模糊”表格状态吗?
                  • @Dev 的评论是正确的,应该添加到接受的答案中。
                  【解决方案14】:

                  在我看来,有一个选项可以改变这个,因为文档说三种选择样式,常规的默认样式是蓝色,看下面的图片..你需要给它发送一条我无法弄清楚的消息因为我以前从未开发过适用于 mac 的应用程序。希望这会有所帮助...!

                  【讨论】:

                  • 你好,selectionHighlightStyleNSTableViewSelectionHighlightStyleRegular,但我不知道如何告诉它如何使用alternatesecondary 选择的颜色...
                  • tableview 处于焦点时显示蓝色。如果不在焦点上,则显示灰色。没有简单的方法可以更改选择颜色。
                  • 这太有道理了。
                  猜你喜欢
                  • 1970-01-01
                  • 2012-07-20
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-02-07
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-06-10
                  • 1970-01-01
                  相关资源
                  最近更新 更多