swiftmacoscocoaappkit

Trying to match text alignment with Date/Time on Status/Menu Bar, but can not


I'm trying to match and vertically align the text (timer/"0:00" in the screenshots) with macOS Time/Date item on the Status Bar.

On the built-in display (white font) it needs baselineOffset: 0.5 to align with Time/Date. External display (black font) does not require such.

However, if screen focus changes to inactive (when clicking mouse on different screen to switch "screen" focus), the alignment changes, but in opposite directions on built-in vs external.

I've tried different resolutions on both 27" 4K and 14" MBP - same result.

                          TLDR table
          (screen active)           (offset is 0)
          vertical offset           screen focus
             0       0.5          active   inactive  

built-in    low      OK             low      OK

external    OK      high            OK      low

Please see the screenshots and the code snippet for more details.

baselineOffset On vs Off (white: built-in, black: external)

baselineOffset On vs Off

active vs inactive screen (white: built-in, black: external)

active vs inactive screen

class AppDelegate: NSObject, NSApplicationDelegate {
    private var statusItem: NSStatusItem!

// ...
 
    private func updateStatusBar() {
        guard let button = statusItem.button else { return }
        
        let title = “0:00”
        
        DispatchQueue.main.async {
            let attributes: [NSAttributedString.Key: Any] = [
                .font: NSFont.systemFont(ofSize: NSFont.systemFontSize, weight: .regular),
                .foregroundColor: NSColor.textColor,
                .baselineOffset: 0.5
            ]
            
            let attributedTitle = NSAttributedString(string: title, attributes: attributes)
            button.attributedTitle = attributedTitle
        }
    }

// ...

}
 
@main
class App {
    static func main() {
        let app = NSApplication.shared
        let delegate = AppDelegate()
        app.delegate = delegate
        app.run()
    }
}

Solution

  • I was able to solve this oddity by converting text into image.

    As far as my testing goes: Liquid Retina (camera notch) has a slightly different vertical alignment for text and will behave oddly (passive vs active desktop focus, aligns opposite ways, etc), unlike all other displays I've checked (external 4K 16:9, M1 Air 16:10).

    However, the images were always aligned, so:

    class AppDelegate {
        //...
        let status: NSMutableAttributedString() = NSAttributedString(string: "Hello World"))
        
        DispatchQueue.main.async {
            let size = status.size()
            let image = NSImage(size: size)image.lockFocus()
            status.draw(at: .zero)
            image.isTemplate = true
            image.unlockFocus()
            button.image = image
        }
    }
    

    Also, Time and Date on macOS is aligned slightly higher than the rest status bar icons/text.