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

如何在SwiftUI Mac应用中实现窗口按行优先网格平铺?

SwiftUI Mac版多窗口行优先网格平铺实现方案

核心平铺逻辑实现

先封装一个全局的窗口平铺工具方法,基于NSApp的窗口列表计算每个窗口的位置和尺寸:

import SwiftUI

extension NSApplication {
    static func tileWindowsInGrid() {
        // 获取主屏幕可用区域(排除菜单栏和Dock)
        guard let screenFrame = NSApp.mainWindow?.screen?.visibleFrame else { return }
        // 筛选可见且未最小化的窗口(可根据需求排除主窗口)
        let targetWindows = NSApp.windows.filter { 
            $0.isVisible && !$0.isMiniaturized 
            // 可选:排除主窗口
            // && $0.identifier?.rawValue != "main"
        }
        guard !targetWindows.isEmpty else { return }
        
        // 自定义窗口最小尺寸(按需调整)
        let minWindowWidth: CGFloat = 300
        let minWindowHeight: CGFloat = 400
        
        // 计算每行最大窗口数
        let maxColumns = Int(screenFrame.width / minWindowWidth)
        let totalWindows = targetWindows.count
        let columns = min(maxColumns, totalWindows)
        let rows = (totalWindows + columns - 1) / columns // 向上取整计算行数
        
        // 计算每个窗口的实际大小(铺满屏幕可用区域)
        let windowWidth = screenFrame.width / CGFloat(columns)
        let windowHeight = screenFrame.height / CGFloat(rows)
        
        // 逐个设置窗口位置(Mac坐标系原点在屏幕左下角)
        for (index, window) in targetWindows.enumerated() {
            let column = index % columns
            let row = index / columns
            
            let originX = screenFrame.origin.x + CGFloat(column) * windowWidth
            let originY = screenFrame.origin.y + screenFrame.height - CGFloat(row + 1) * windowHeight
            
            window.setFrame(NSRect(x: originX, y: originY, width: windowWidth, height: windowHeight), display: true)
        }
    }
}

1. 创建窗口时自动平铺

在触发新窗口创建的逻辑后,延迟调用平铺方法(确保新窗口已加入窗口列表):

// 示例:打开新子游戏窗口的按钮
Button("添加新游戏窗口") {
    // 打开指定ID的窗口
    NSApp.openWindow(id: "wordle-subgame")
    // 延迟执行平铺,确保窗口初始化完成
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        NSApplication.tileWindowsInGrid()
    }
}

2. 添加「平铺窗口」菜单选项

在App结构体中通过CommandMenu扩展系统「窗口」菜单:

@main
struct WordleHelperApp: App {
    var body: some Scene {
        WindowGroup(id: "main") {
            MainView()
        }
        
        WindowGroup(id: "wordle-subgame") {
            WordleSubgameView()
        }
        
        // 扩展窗口菜单
        CommandMenu("窗口") {
            Button("平铺窗口") {
                NSApplication.tileWindowsInGrid()
            }
            .keyboardShortcut("T", modifiers: [.command, .shift]) // 可选:添加快捷键
        }
    }
}

可选优化点

  • 可根据窗口数量动态调整列数(比如4个窗口用2列,8个用3列),替代按最小宽度计算的逻辑
  • 支持保留窗口的最小尺寸限制,当屏幕空间不足时自动滚动
  • 可以记忆用户调整后的窗口布局,避免每次平铺都强制覆盖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:52:41