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

SwiftUI开发Mac状态栏应用:如何调用字体选择器并获取结果?

在SwiftUI Mac状态栏应用中触发字体选择器并捕获结果(Xcode 11.7)

当然可以实现!在Xcode 11.7的SwiftUI Mac状态栏应用里,由于SwiftUI本身没有原生的字体选择器组件,我们可以借助AppKit的NSFontPanel来完成这个需求,下面是具体的实现步骤和代码示例:

1. 创建字体状态管理器

首先我们需要一个ObservableObject来管理选中的字体状态,同时封装触发字体选择器和处理结果的逻辑:

import SwiftUI
import AppKit

class FontManager: ObservableObject {
    // 用@Published标记,让SwiftUI视图能监听字体变化
    @Published var selectedFont: NSFont = .systemFont(ofSize: 14)
    
    func showFontPicker() {
        let fontPanel = NSFontPanel.shared
        // 设置当前选中的字体作为面板初始值
        fontPanel.setPanelFont(selectedFont, isMultiple: false)
        // 弹出字体选择器
        fontPanel.makeKeyAndOrderFront(nil)
        // 设置代理来捕获用户选择的结果
        fontPanel.delegate = self
    }
}

// 实现NSFontPanelDelegate协议,处理字体选择回调
extension FontManager: NSFontPanelDelegate {
    func fontPanel(_ sender: NSFontPanel, didChangeFont font: NSFont?) {
        guard let newFont = font else { return }
        // 更新选中的字体状态,SwiftUI视图会自动刷新
        selectedFont = newFont
        // 这里可以添加自定义的业务逻辑,比如保存字体设置
        print("已选中字体:\(newFont.displayName ?? "未知字体"),大小:\(newFont.pointSize)")
    }
}

2. 构建弹出窗口的SwiftUI视图

接下来创建弹出窗口的内容视图,添加触发按钮并展示选中的字体信息:

struct PopupView: View {
    // 注入FontManager实例,监听字体状态变化
    @ObservedObject var fontManager = FontManager()
    
    var body: some View {
        VStack(spacing: 20) {
            Text("当前选中字体")
                .font(.headline)
            
            Text("\(fontManager.selectedFont.displayName ?? "未选择字体")")
            Text("字体大小:\(fontManager.selectedFont.pointSize, specifier: "%.1f")")
            
            Button("打开字体选择器") {
                fontManager.showFontPicker()
            }
            .padding(.horizontal, 16)
            .padding(.vertical, 8)
            .background(Color.accentColor)
            .foregroundColor(.white)
            .cornerRadius(6)
        }
        .padding(24)
        .frame(width: 300)
    }
}

3. 配置状态栏应用的核心逻辑

最后我们需要设置状态栏项目和弹出窗口的显示逻辑,这部分需要借助AppKit的NSStatusItem和NSWindow:

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    var statusItem: NSStatusItem!
    var popupWindow: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 创建状态栏项目
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        
        // 设置状态栏按钮的图标和点击事件
        if let button = statusItem.button {
            button.image = NSImage(systemSymbolName: "textformat", accessibilityDescription: "字体选择工具")
            button.action = #selector(togglePopup(_:))
        }
        
        // 创建无标题栏的弹出窗口,包裹SwiftUI视图
        let popupView = PopupView()
        popupWindow = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 300, height: 200),
            styleMask: [.borderless],
            backing: .buffered,
            defer: false
        )
        popupWindow.contentView = NSHostingView(rootView: popupView)
        // 关闭窗口时不释放,避免重复创建崩溃
        popupWindow.isReleasedWhenClosed = false
        // 设置窗口层级为状态栏级别
        popupWindow.level = .statusBar
    }

    // 切换弹出窗口的显示/隐藏状态
    @objc func togglePopup(_ sender: Any?) {
        if popupWindow.isVisible {
            popupWindow.orderOut(nil)
        } else {
            // 将窗口定位到状态栏按钮的正下方
            if let button = statusItem.button {
                let buttonFrame = button.window!.frame
                popupWindow.setFrameOrigin(NSPoint(
                    x: buttonFrame.origin.x + buttonFrame.width/2 - popupWindow.frame.width/2,
                    y: buttonFrame.origin.y - popupWindow.frame.height
                ))
            }
            popupWindow.orderFront(nil)
        }
    }
}

关键注意事项

  • Xcode 11.7中,SwiftUI视图需要通过NSHostingView才能嵌入到AppKit的NSWindow中。
  • 确保popupWindow的isReleasedWhenClosed设为false,否则关闭窗口后再次打开会导致崩溃。
  • NSFontPanel是系统全局共享的面板,所以不需要手动销毁,用户关闭面板后会自动隐藏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:12:55