【问题标题】:View based NSTableView selection highlighting基于视图的 NSTableView 选择突出显示
【发布时间】:2014-02-07 02:36:54
【问题描述】:

我正在尝试将 iOS 应用程序移植到 Mac 上,但在转换过程中遇到了一些问题。其中之一是NSTableView的自定义。 NSCellNSTableRowView 和基于 NSTableview 的自定义 NSView 之间到底有什么区别?我最初从基于NSTableView 的视图开始,但我很快注意到我必须自己处理选择。我无法做到这一点,所以我继续使用NSTableRowView,奇怪的是,它不会调用我的自定义NSTableRowView 的初始化程序。

我基本上只想要一个带有自定义内容的自定义表格视图单元格,它是可选的。最好的方法是什么?

在 iOS 上,我只需继承 UITableViewCell 并设置其 selectedView 属性。在 Mac 上,这似乎比这更复杂。

【问题讨论】:

    标签: objective-c macos nstableview nstableviewcell


    【解决方案1】:

    毕竟你可以在 IB 中设置它,它是设置“突出显示”,在“样式”下,在“交替行”复选框上方。设置为“无”,等等:

    【讨论】:

      【解决方案2】:

      我实际上刚刚(在​​侧边栏中)发现了这个问题,它建议子类化NSTableRowView。我之前已经这样做了,但是没有用。我再次尝试了它,令人惊讶的是它现在可以工作了......

      Handling custom selection style in view based NSTableView

      但是,此答案的信息量不是很大,因此我将尝试介绍我为完成这项工作所做的工作。

      首先,我实现了下面的NSTableView委托方法并返回nil!

      - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
      
          return nil;
      
      }
      

      为了使用基于视图的表(我猜 NSTableViewRow 也被视为基于视图的表...),您必须实现此方法。我不太确定我可能做错了什么,但是如果没有这种方法,我的单元格将不会显示!

      确保不要让 NSTableView 通过设置此属性来处理任何选择:

      yourNSTableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;
      

      好的,现在我们要使用以下委托方法设置我们的单元格:

      -(NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row{
      
          static NSString *cellID = @"cell_identifier";
      
          //use this if you want to reuse the cells
          CustomTableRowView *result = [tableView makeViewWithIdentifier:cellID owner:self];
      
          if (result == nil) {
      
              result = [[CustomTableRowView alloc] initWithFrame:NSMakeRect(0, 0, self.frame.size.width, 80)];
              result.identifier = cellID;
      
          }
      
          result.data = [tableData objectAtIndex:row];
      
          // Return the result
          return result;
      
      }
      

      好的,现在继承NSTableRowView 并实现/覆盖以下两个方法:

      首先,我们必须覆盖setSelected: 以使单元格在被选中时重绘其背景。所以这里是:

      -(void)setSelected:(BOOL)selected{
      
          [super setSelected:selected];
          [self setNeedsDisplay:YES];
      
      }
      

      如前所述,我们调用setNeedsDisplay: 以便单元格重绘其背景。

      最后是绘图代码。像这样覆盖方法drawBackgroundInRect:

      -(void)drawBackgroundInRect:(NSRect)dirtyRect{
          if (!self.selected) {
              [[NSColor clearColor] set];
          } else {
              [someColor set];
          }
          NSRectFill(dirtyRect);
      }
      

      【讨论】:

      • 我发现我不需要第一位,但其余的帮助所以 +1。谢谢。
      • @lateAtNight 很高兴它有帮助:)
      • 如果它对其他人有帮助,我试图在 10.9 上使用 Swift 来实现这一点,但获取 CGContextRef 有点不同。请参阅此答案以获取帮助:stackoverflow.com/a/24056236/2708274
      【解决方案3】:

      the_critic 在 Swift 中的解决方案:(使用 XCode 7 beta3、Swift 2.0 测试)

      class CustomTableRowView: NSTableRowView {
      
          override var selected: Bool {
              willSet(newValue) {
                  super.selected = newValue;
                  needsDisplay = true
              }
          }
      
          override func drawBackgroundInRect(dirtyRect: NSRect) {
              let context: CGContextRef = NSGraphicsContext.currentContext()!.CGContext
      
              if !self.selected {
                  CGContextSetFillColorWithColor(context, NSColor.clearColor().CGColor)
              } else {
                  CGContextSetFillColorWithColor(context, NSColor.redColor().CGColor)
              }
      
              CGContextFillRect(context, dirtyRect)
          }
      
      }
      

      视图控制器:

      class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
      
          // [...]
      
          func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
              guard let rowView = tableView.makeViewWithIdentifier("RowView", owner: nil) as! CustomTableRowView? else {
                  let rowView = CustomTableRowView()
                  rowView.identifier = "RowView"
                  return rowView
              }
      
              return rowView
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        使用以下代码响应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];
        

        【讨论】:

        • 如果单击其他应用程序而不是跳回该应用程序,所选行将再次变为蓝色。
        • 设置 NSTableViewSelectionHighlightStyleNone 似乎已经完全摆脱了蓝色选择,即使没有 setEmphasized! (macOS 10.15 Catalina)
        猜你喜欢
        • 2012-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-21
        • 2013-12-02
        • 1970-01-01
        • 1970-01-01
        • 2017-03-24
        相关资源
        最近更新 更多