You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义NSTableCellView文字被动态条形遮挡,如何用CGBlendMode.exclusion处理?

解决NSTableCellView动态条形遮挡文本的问题

问题背景

我自定义了NSTableCellView,单元格内有随数值动态变化长度的彩色条形(范围0-100%),但黑色文本落在黑色条形上时会被遮挡。已知用.exclusion混合模式可以解决这个问题,但之前从未实现过该功能,代码库也没有同类实现。参考PDF页面渲染的自定义高亮代码写了部分代码,却不知道如何正确设置上下文及完成实际绘制(当时上下文由PDFKit提供)。

当前代码:

class BarTableCellView: NSTableCellView {

    @IBOutlet var bar1: NSBox!
    @IBOutlet var bar1Width: NSLayoutConstraint!
    @IBOutlet var bar2: NSBox!
    @IBOutlet var bar2Width: NSLayoutConstraint!
    
    override func draw(_ dirtyRect: NSRect) {
        
        super.draw(dirtyRect)

        // Drawing code here.
        
        let context = NSGraphicsContext.current
        context?.saveGraphicsState()
     
        context.setBlendMode(CGBlendMode.exclusion)
    }   
} 

解决方案

核心是调整绘制顺序,先绘制条形,再用exclusion混合模式绘制文本,同时严格管理图形状态,避免影响其他视图绘制。

修改后的完整代码:

class BarTableCellView: NSTableCellView {

    @IBOutlet var bar1: NSBox!
    @IBOutlet var bar1Width: NSLayoutConstraint!
    @IBOutlet var bar2: NSBox!
    @IBOutlet var bar2Width: NSLayoutConstraint!
    
    override func draw(_ dirtyRect: NSRect) {
        guard let context = NSGraphicsContext.current?.cgContext else {
            super.draw(dirtyRect)
            return
        }
        
        // 保存初始图形状态
        context.saveGState()
        
        // 先绘制基础元素(包括条形和默认文本)
        super.draw(dirtyRect)
        
        // 恢复初始状态后,设置exclusion混合模式
        context.restoreGState()
        context.saveGState()
        
        context.setBlendMode(.exclusion)
        
        // 重新绘制文本,应用混合模式
        if let textField = textField, let text = textField.stringValue as NSString? {
            let textAttrs = textField.attributedStringValue.attributes(at: 0, effectiveRange: nil)
            text.draw(in: textField.frame, withAttributes: textAttrs)
        }
        
        // 恢复图形状态,避免污染其他绘制操作
        context.restoreGState()
    }
}

关键细节

  • 绘制顺序:必须让条形先完成绘制,再在混合模式下绘制文本,这样重叠部分会触发exclusion效果——黑色文本在黑色条形上会显示为白色,保证文本可读性。
  • 图形状态管理:每次修改上下文属性前调用saveGState(),绘制完成后调用restoreGState(),防止上下文设置影响其他视图的正常绘制。
  • 手动重绘文本:由于super.draw()已经默认绘制了一次文本,需要在混合模式下重新绘制一次文本,覆盖原有效果,实现混合模式的应用。

如果NSBox条形的层级在文本上方,也可以直接调整子视图顺序(将文本字段移到条形视图上层),再结合上述混合模式设置,能达到同样效果。

内容的提问来源于stack exchange,提问作者Jc Nolan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 01:50:25