UI 預覽優先 (TinyCorn Studio 標準)
規則: 所有介面變更都必須在套用到程式碼之前,提供預覽圖供使用者核准。
工作流程
-
在
tools/preview_<名稱>.swift中撰寫離屏渲染腳本 — 無需執行應用程式,直接渲染為 2x PNG。 -
執行並為使用者開啟圖片:
swift tools/preview_<名稱>.swift ~/Desktop/<App>-<名稱>-Preview.png open ~/Desktop/<App>-<名稱>-Preview.png -
請求核准 — 如果有多個設計方案,並排渲染 2-4 個選項,並請使用者選擇 (A/B/C/D)。
-
僅在使用者確認後才套用。 將預覽腳本連同功能一同提交。
-
如果使用者要求修改:編輯腳本,重新渲染,重複直到核准為止。
程式碼骨架 (SwiftUI, macOS)
import AppKit
import SwiftUI
struct PreviewRoot: View {
var body: some View {
// 使用應用程式實際的元件/顏色建構模擬 UI
VStack { /* ... */ }
.frame(width: 900, height: 600)
.background(Color(nsColor: .windowBackgroundColor))
}
}
let host = NSHostingView(rootView: PreviewRoot())
host.frame = NSRect(x: 0, y: 0, width: 900, height: 600)
host.layoutSubtreeIfNeeded()
let rep = host.bitmapImageRepForCachingDisplay(in: host.bounds)!
host.cacheDisplay(in: host.bounds, to: rep)
let png = rep.representation(using: .png, properties: [:])!
let out = CommandLine.arguments.count > 1
? CommandLine.arguments[1]
: "preview.png"
try! png.write(to: URL(fileURLWithPath: out))
print("Wrote \(out)")
常見陷阱 (實際遇過)
- 不要使用與 SwiftUI 修飾符/檢視同名的全域變數 (例如
border) → 會導致多載錯誤。請使用borderColor。 - 標頭在多個方法間共用,因此在同一個檔案的其他地方不要重複宣告。
- 渲染 2x:設定
rep.size,或像上面那樣使用bitmapImageRepForCachingDisplay+cacheDisplay;在快取之前記得呼叫layoutSubtreeIfNeeded()。 - 請勿使用
screencapture/AppleScript 來擷取應用程式 — 機器通常缺乏螢幕錄製權限 (-1743)。離屏渲染是唯一可靠的方法。 - 深色主題的應用程式:使用相同的
Color(nsColor:)和應用程式的素材資源,使預覽與實際情況一致。 - 將圖片儲存到
~/Desktop/,方便使用者尋找,檔名格式為<App>-<功能>-Preview.png。
超越 SwiftUI
- 網頁:在瀏覽器中開啟 HTML 模型圖並截圖,或使用 Playwright 螢幕截圖。
- CLI/TUI:在終端機中使用 ANSI 渲染,或使用帶有顏色的文字描述。
不變的總體原則:先預覽,後程式碼,經使用者核准才套用。