本介紹描述了 Flutter 所使用的宣告式風格與許多其他 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.

在命令式風格中,你通常會找到 ViewB 的所有者,使用選擇器或 `findViewById` 或類似方法檢索例項 `b`,並對其呼叫變異(並隱式使其失效)。例如

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

你可能還需要在 ViewB 的建構函式中複製此配置,因為 UI 的真理源可能會比例項 `b` 本身更長壽。

在宣告式風格中,檢視配置(例如 Flutter 的 Widget)是不可變的,並且只是輕量級的“藍圖”。要改變 UI,widget 會觸發自身的重建(在 Flutter 中最常見的是透過在 StatefulWidget 上呼叫 `setState()`),並構建一個新的 Widget 子樹。

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

在這裡,當 UI 改變時,Flutter 不是變異舊例項 `b`,而是構造新的 Widget 例項。框架在幕後使用 RenderObject 管理傳統 UI 物件的許多職責(例如維護佈局狀態)。RenderObject 在幀之間持續存在,Flutter 的輕量級 Widget 會告訴框架在狀態之間變異 RenderObject。Flutter 框架會處理其餘部分。