WWDC25

2025 年 6 月 22 日

探索 WWDC25 賦予 SwiftUI AttributedString 的五個黑科技

已複製到剪貼板


從純文字到「豐富」體驗的躍進

身為資深開發者,我們都深知從單純的 String 跨越到富文本編輯時的痛處。當應用程式需要支援加粗、顏色標記,甚至是整合 Genmoji 或處理複雜的雙向語系(如希伯來語與英語混排)時,傳統的字串處理往往會演變成一場災難。

在 WWDC25 中,Apple 透過 SwiftUI 與 AttributedString 的深度整合,將富文本編輯從瑣碎的底層計算提升到了藝術創作的層次。現在,建構一個專業的編輯器不再是勞心勞力的苦差事,而更像是在製作一個層次分明的「牛角麵包」-只要掌握正確的材料與工法,你就能在 SwiftUI 中實現精準且優雅的文字體驗。

WWDC 2025
WWDC 2025

架構的翻轉:模糊編輯與靜態呈現的邊界

在過去,TextEditor 僅能處理純文字,但現在我們迎來了一個重大的架構轉變。你只需將綁定的狀態從 String 改為 AttributedString,應用程式便能實現從「純文字框」到「專業編輯器」的降維打擊。

這不只是資料類型的改變,而是解鎖了系統級的原生支援。當你完成這一步,TextEditor 將獲得與不可編輯的 Text 元件完全一致的語義化能力:

  • 系統級格式控制:直接支援加粗、傾斜、下劃線及字級調整的系統 UI
  • Genmoji 深度整合:使用者可直接輸入 Genmoji,並在底層以屬性化方式完美呈現
  • 語義化適應:透過 SwiftUI 的 FontColor 屬性,自動獲得 Dark Mode 與 Dynamic Type 的原生支援
  • 無縫呈現:編輯器內的屬性(如字距 Kerning、追蹤 Tracking、行高)能完美導出至 Text 顯示,確保視覺的一致性

打破「連續選擇」的迷思:RangeSet 與雙向文本

傳統開發邏輯中,我們習慣用單一的 Range 來代表選取範圍,但在現代化的多語系應用中,這是一個危險的假設。

當英文(左至右)與希伯來文(右至左)混排時,儘管視覺上看起來是一個連續的選擇,但在底層的邏輯順序 (Logical Order) 中,它實際上是由多個不連續的範圍組成的。

這就是為什麼 AttributedString 現在全面支援使用 RangeSet 進行切片(Slicing)。這項進化的核心在於,系統不再強迫將視覺佈局 (Visual Layout) 擠壓進單一範圍,而是允許開發者透過 RangeSet 精準掌控不連續的子字串選擇,解決雙向語系下的選取難題。

路徑的脆弱性:揭開樹狀結構與索引失效的真相

許多開發者在操作 AttributedString 時常遇到索引崩潰,這源於對底層結構的誤解。AttributedString 並非字元陣列,而是以 樹狀結構 (Tree Structure) 儲存。所謂的索引(Index),本質上是這棵樹中的路徑 (Paths)。

這意味著:任何細微的變動都會改變樹的佈局,導致所有舊路徑(索引)立即失效。 就像烹飪時使用過期的食材,使用過時的索引只會導致崩潰或錯誤。

開發者的 Dos and Don'ts:

  • Don't:嚴禁將修改前的索引儲存在變數中供後續使用
  • Do:使用 transform(updating:) 函數。這個 API 會提供一個閉包,讓你執行文本修改。最重要的技術細節是,當閉包結束時,它會自動將你傳入的選取範圍更新為新的路徑,作為語義錨點 (Semantic Anchor) 確保游標不會因樹狀結構變動而莫名跳轉
  • Do:在批量修改前,先將 Ranges 轉換為 RangeSet 進行一次性處理,避免在循環中因不斷變動而產生過時索引

讓編輯器變聰明:屬性值約束與「探測」機制

如果你想限制編輯器僅能使用特定格式(例如:在食譜 App 中,只有「成分」可以標記為綠色),WWDC25 提供的 AttributedTextFormattingDefinitionAttributedTextValueConstraint 是你的最佳工具。

這裡隱藏了一個關鍵的架構細節:探測 (Probing) 機制。當你定義了約束(如:非成分文字不能為綠色),TextEditor 會主動「探測」這些約束。如果使用者嘗試進行不合法的色彩修改,系統會預先判斷該變更無效,並直接在 UI 層級禁用相關控制項。這讓開發者無需手動編寫繁瑣的 UI 切換邏輯,即可確保資料的完整性。

掌控屬性生命週期:無效條件與標量視圖

為了讓編輯體驗更符合直覺,資深架構師必須關注屬性如何隨著輸入而「流動」:

  • 成長控制 Inheritance:透過 inheritedByAddedText 屬性決定新輸入的文字是否承接屬性。例如,拼寫檢查的底線應設為 false,因為新文字尚未經過驗證
  • 誠信維護 Invalidation:invalidationConditions 允許你設定在「文字改變 textChanged」時自動移除屬性。這能避免使用者修改文字後,陳舊的標記(如過時的拼寫錯誤提示)殘留在畫面上
  • 段落邊界 Run Boundaries:Foundation 現在支援將屬性(如對齊方式)限制在段落邊緣 (Paragraph Edges) 或特定字元邊緣。這強制屬性必須應用於整個段落,即使使用者僅選取了一個單字,系統也會自動擴張範圍

專業架構師必知

AttributedString 現在提供 UTF-8 與 UTF-16 標量視圖 (Scalar Views)。這與字元視圖 (Character View) 共享相同的索引,極大簡化了與 NSString 或其他低階 API 對接時的轉換痛苦。

為您的應用程式撒上一點「魔法」

AttributedString 在 WWDC25 的進化,標誌著 SwiftUI 在處理複雜文本上已進入成熟期。透過強大的約束協議與精密的索引管理,技術門檻已然消失,剩下的便是開發者的創意。

您將如何利用這些精細的屬性控制,重新定義應用程式中的輸入體驗?

進階行動建議

除了基本的 TextEditor 升級,建議進一步探索 Transferable Wrapper,實現無損的 RTFD 導出與拖放功能;或結合 SwiftData 實現富文本的持久化。現在就下載範例專案,為您的使用者帶來更具表現力的產品體驗!

分享文章

已複製到剪貼板

主題文章

查看 WWDC25

超級感謝

關於 XcodeProject

XcodeProject 創立於 2023,致力於協助開發者探索 Apple 的創新世界,學習在 iOS、iPadOS、macOS、tvOS、visionOS 與 watchOS 上開發 App,發現眾多技術與框架,讓開發者獲得更多能力。


Contacts

Ricky Chuang

XcodeProject

RickyChuang.xcodeproj@gmail.com

XcodeProject 聯絡

contact.xcodeproj@gmail.com

最新文章