如何在NSStatusBarButton的自定义NSView中并排绘制两张图片?
你遇到的问题核心是自定义NSView没有正确设置尺寸和布局,导致添加到状态栏按钮后完全无法显示。另外直接用draw(_:)绘制图片的方式虽然可行,但实现并排双图会比较繁琐,我给你两种解决方案,推荐第二种更简洁的Auto Layout实现方式。
先分析你的代码问题
- 无尺寸/布局设置:你创建
statusBarView()后直接addSubview,但这个View没有任何尺寸信息,状态栏按钮不知道要给它分配多大空间,所以完全看不到。 - 图片加载不安全:强制解包
myimage!如果图片不存在会直接崩溃,建议用可选绑定处理。 dirtyRect的局限性:用dirtyRect绘制图片会导致图片跟随重绘区域变形,应该用View自身的bounds来保证显示完整。
方案一:修正自定义Draw方式(支持单/双图绘制)
先修改你的statusBarView,设置固有尺寸让状态栏按钮识别它的大小,再在draw(_:)里正确绘制两张图片:
import Cocoa class StatusBarView: NSView { // 开放图片属性,方便外部设置 var leftImage: NSImage? var rightImage: NSImage? // 设置视图固有尺寸,让状态栏按钮知道该分配的空间 override var intrinsicContentSize: NSSize { // 假设单图20x20,双图加2间距,总尺寸42x20 return NSSize(width: 42, height: 20) } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let imageSize = NSSize(width: 20, height: 20) let spacing: CGFloat = 2 let centerY = (bounds.height - imageSize.height)/2 let startX = (bounds.width - imageSize.width*2 - spacing)/2 // 绘制左图 if let leftImg = leftImage { let leftRect = NSRect(x: startX, y: centerY, width: imageSize.width, height: imageSize.height) leftImg.draw(in: leftRect) } // 绘制右图 if let rightImg = rightImage { let rightRect = NSRect(x: startX + imageSize.width + spacing, y: centerY, width: imageSize.width, height: imageSize.height) rightImg.draw(in: rightRect) } } }
添加到状态栏按钮时,记得用Auto Layout约束固定位置:
// 实例化自定义View并设置图片 let customView = StatusBarView() customView.leftImage = NSImage(named: "LeftStatusImage") customView.rightImage = NSImage(named: "RightStatusImage") if let button2 = statusItem2.button { button2.addSubview(customView) // 关闭自动布局掩码,手动添加约束 customView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ customView.leadingAnchor.constraint(equalTo: button2.contentView.leadingAnchor, constant: 4), customView.trailingAnchor.constraint(equalTo: button2.contentView.trailingAnchor, constant: -4), customView.topAnchor.constraint(equalTo: button2.contentView.topAnchor, constant: 2), customView.bottomAnchor.constraint(equalTo: button2.contentView.bottomAnchor, constant: -2) ]) }
方案二:用NSStackView+NSImageView实现(推荐,更易维护)
不需要自定义draw(_:),直接用系统的NSStackView横向排列两个NSImageView,Auto Layout会自动处理布局,代码更简洁:
import Cocoa // 创建并排图片的组合View func createStatusBarImageView() -> NSView { let stackView = NSStackView() stackView.orientation = .horizontal stackView.spacing = 2 // 两张图的间距 stackView.alignment = .centerY // 左图片 let leftImageView = NSImageView(image: NSImage(named: "LeftStatusImage")!) leftImageView.imageScaling = .scaleProportionallyUpOrDown leftImageView.setContentHuggingPriority(.defaultHigh, for: .horizontal) // 右图片 let rightImageView = NSImageView(image: NSImage(named: "RightStatusImage")!) rightImageView.imageScaling = .scaleProportionallyUpOrDown rightImageView.setContentHuggingPriority(.defaultHigh, for: .horizontal) stackView.addArrangedSubview(leftImageView) stackView.addArrangedSubview(rightImageView) // 设置内边距,避免图片紧贴状态栏边缘 stackView.edgeInsets = NSEdgeInsets(top: 2, left: 4, bottom: 2, right: 4) return stackView }
添加到状态栏按钮:
if let button2 = statusItem2.button { let statusImageView = createStatusBarImageView() button2.addSubview(statusImageView) // 约束让组合View填满按钮 statusImageView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ statusImageView.leadingAnchor.constraint(equalTo: button2.leadingAnchor), statusImageView.trailingAnchor.constraint(equalTo: button2.trailingAnchor), statusImageView.topAnchor.constraint(equalTo: button2.topAnchor), statusImageView.bottomAnchor.constraint(equalTo: button2.bottomAnchor) ]) }
额外注意事项
- 确保图片资源已正确添加到项目,名称完全匹配(macOS文件名区分大小写)
- 给
statusItem2设置合适的长度,比如statusItem2.length = NSStatusItem.variableLength,避免图片被截断 - 如果你用的是macOS 10.11+,Auto Layout是首选,比手动设置Frame更适配不同状态栏尺寸
内容的提问来源于stack exchange,提问作者Cemal K
相关产品推荐
相关产品推荐

