首页 > 解决方案 > 使用 - (BOOL)tableView:isGroupRow 时,NSAttributedString 的格式在 NSTableCellView / NSTableView 中消失:

问题描述

我正在使用一个应用程序,我想将 NSTableView 中的所有单元格组合起来作为其下方行的节标题。我正在使用的一种解决方案是使用 - (BOOL)tableView:isGroupRow: 这在一定程度上起作用,但不幸的是,我在 NSTextField 上使用的格式在使用 isGroupRow 时会被破坏,文本应该是白色的,并且无论是否显示粗体不管我设置与否。

Clobbered Formatting - 应该是白色和粗体出现

在示例代码中,如果您取消注释该行// return falsetableView(_ tableView: NSTableView, isGroupRow row: Int)您将看到正确的格式正常工作(当然该字段显示两次,因为它没有被转换为组行

如果禁用 isGroupRow,格式化就可以正常工作

该解决方案需要几个步骤,完整的示例项目可以在https://github.com/jcnolan/NSTableViewIsGroupRowTest找到

这是我的 tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    
    var text: String = "Doh!"
    var aText: NSAttributedString? = nil
    var cellIdentifier: CellIdentifiers? = nil
    
    guard let item = tableData?[row] else { return nil }
    
    if let tableColumn = tableColumn { cellIdentifier = CellIdentifiers(rawValue: String(describing: tableColumn.identifier.rawValue)) }
    else                             { cellIdentifier = CellIdentifiers.pageCell } // When "groupRow" is true there is no column, so use first column whatever that is

    if let _ = item.title { cellIdentifier = CellIdentifiers.titleRow } // hack
    
    guard let cellIdentifier = cellIdentifier else { return nil }
    
    if let cell = tableView.makeView(withIdentifier: cellIdentifier.uiiId, owner: nil) as? NSTableCellView {
        
        switch cellIdentifier {
        
        case .pageCell:     text = item.page?.description ?? "page unk"; break
        case .commentCell:  text = item.comment ?? "comment unk"; break
            
        case .titleRow:     text = item.title ?? "title unk"
                            var attributes = [NSAttributedString.Key: AnyObject]()
                            attributes[.foregroundColor] = NSColor.white
                            attributes[.font] = NSFont.boldSystemFont(ofSize: 13.0)
                            aText = NSAttributedString(string: text, attributes: attributes)
        }
        
        if let aText = aText { cell.textField?.attributedStringValue = aText }
        else                 { cell.textField?.stringValue = text }
        
        return cell
    }
    return nil
}

而我的 tableView(_ tableView: NSTableView, isGroupRow row: Int)

func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
    
    // return false  // Uncomment this to see NSAttributedString working in standard row
    
    guard let item = tableData?[row], let title = item.title else { return false }
    return true // only if item exists and it's a tittle
}

该解决方案还需要 func tableView(_ tableView: NSTableView, rowViewForRow row: Int)

func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
    
    // Required for changing table highlighting
    
    guard let item = tableData?[row] else { return nil }
    
    let retVal:TintedTableRowView? = TintedTableRowView()
    
    if let retVal = retVal {
        retVal.isTitleRow = item.title != nil
    }
    
    return retVal
}

class TintedTableRowView: NSTableRowView {

var isTitleRow:  Bool = false

override func draw(_ dirtyRect: NSRect) {
   
    if self.selectionHighlightStyle != .none || true {
        
        var bgcol:NSColor = NSColor.clear
        
        switch isTitleRow {
        case true: bgcol = NSColor.lightGray
        default:   bgcol = NSColor.clear }
        
        let selectionRect = NSInsetRect(self.bounds, 0, 0)
        bgcol.setStroke()
        bgcol.setFill()
        let selectionPath = NSBezierPath.init(roundedRect: selectionRect, xRadius: 0, yRadius: 0)
        selectionPath.fill()
        selectionPath.stroke()
    }
}

}

基于字体自动加粗的事实,我猜还需要另一条路径来告诉 Swift 如何格式化组行?我已经为这个问题苦苦挣扎了好几天了......任何帮助将不胜感激。

编辑:检查文档有一个参考“当配置为源列表样式表视图时,标识为组行的行以源列表独有的特定样式绘制。” 但是,我没有使用“源列表”样式并在情节提要编辑器和通过代码中将其显式更改为“普通”似乎没有效果。

EDIT2:对数据集提出了额外的请求......虽然我很确定这与 isGroupRow 有关,完整的项目可以在https://github.com/jcnolan/NSTableViewIsGroupRowTest看到。这是数据集和 viewDidLoad():

struct TableDataItem {
       var title: String? = nil
       var page: Int? = nil
       var comment: String? = nil
   }     

override func viewDidLoad() {
        
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        tableView.delegate = self
        tableView.dataSource = self
        tableView.floatsGroupRows = false
        
        installStubData()
        tableView.reloadData()
    }
    
    func installStubData() {
        
        tableData = []
        tableData!.append(TableDataItem(title: "This is doc title 1", page: nil, comment: nil))
        tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 1, page one comment"))
        tableData!.append(TableDataItem(title: nil, page: 2, comment: "this is doc 1, page two comment"))
        tableData!.append(TableDataItem(title: nil, page: 3, comment: "this is doc 1, page three comment"))
        tableData!.append(TableDataItem(title: "This is doc title 2", page: nil, comment: nil))
        tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 2, page one comment"))
        tableData!.append(TableDataItem(title: "This is doc title 3", page: nil, comment: nil))
        tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 3, page one comment"))
        tableData!.append(TableDataItem(title: nil, page: 2, comment: "this is doc 3, page two comment"))
    }

标签: swiftmacoscocoanstableviewnsattributedstring

解决方案


推荐阅读