宣告式 UI 介紹

這篇介紹描述了 Flutter 所使用的宣告式 UI 和許多其他 UI 框架所使用的命令式 UI 的概念性差異

為什麼是宣告式 UI?

從 Win32 到 Web 再到 Android 和 iOS,框架通常使用一種命令式的程式設計風格來完成 UI 程式設計。這可能是你最熟悉的風格——手動建構一個全功能的 UI 例項,比如一個 UIView 或其他類似的內容,在隨後 UI 發生變化時,使用方法或 Setter 修改它。

為了減輕開發人員的負擔,無需編寫如何在不同的 UI 狀態之間進行切換的程式碼, Flutter 相反,讓開發人員描述當前的 UI 狀態,並將轉換交給框架。

然而,這需要稍微改變下如何操作 UI 的思考方式。

如何在命令式框架中修改 UI

思考像下面這樣一個簡單的例子:

View B (contained by view A) morphs from containing two views, c1 and c2, to containing only view c3

在命令式風格中,你通常需要使用選擇器 findViewById 或類似函式獲取到 ViewB 的例項 b 和所有權,並呼叫相關的修改的方法(並隱含的使其失效)。例如:

// Imperative style
b.setColor(red)
b.clearChildren()
ViewC c3 = new ViewC(...)
b.add(c3)

由於 UI 真實的來源可能比例項 b 本身的存活週期更長,你可能還需要在 ViewB 的建構函式中複製此配置。

在宣告式風格中,檢視配置(如 Flutter 的 Widget )是不可變的,它只是輕量的「藍圖」。要改變 UI,widget 會在自身上觸發重建(在 Flutter 中最常見的方法是在 StatefulWidget 上呼叫 setState())並構造一個新的 Widget 子樹。

// Declarative style
return ViewB(
  color: red,
  child: const ViewC(),
);

在這裡,當用戶介面發生變化時,Flutter 不會修改舊的例項 b,而是構造新的 widget 例項。框架使用 RenderObject 管理傳統 UI 物件的職責(比如維護佈局的狀態)。 RenderObject 在幀之間保持不變, Flutter 的輕量級 widget 通知框架在狀態之間修改 RenderObject, Flutter 框架則處理其餘部分。