一、源起
作者是名超大齡程式設計師,曾涉及了包括Web端、桌面端、移動端等各類前端技術,深受這些前端技術的苦,主要但不限於:
- 每種技術編寫程式碼的語言及技術完全不同,同樣呈現形式的元件各端無法通用;
- 大部分前端開發語言跟後端開發語言不同,不能共用一些資料結構;
前端UI的本質是在顯示器上呈現由畫素點組成的畫面,並且響應外部輸入事件作出相應的重繪。由於作者對Skia2D繪圖引擎比較熟悉,又恰好可以借鑑一下Flutter引擎的跨端實現,所以作者動起了重新造一個跨端UI的念頭。 阿基米德說過:“給我一個支點,我可以撬動地球”,那作者要說:"給我一塊畫布,我可以造一個全新的跨端UI"。
二、畫布及畫筆:
有了畫布才能繪製使用者介面,目前畫布的來源主要是兩類:
- Web端參考Flutter的實現,利用編譯為WebAssembly的CanvasKit提供;
- 桌面端及移動端參考Xamarin的實現,利用原生作業系統的視窗結合Skia的SkCanvas提供;
每個窗體的畫布分為兩層,一層繪製Widget,另一層用於彈出層的繪製及一些元件裝飾器的繪製。繪製引擎暫統一由Skia來處理,將來可能會考慮抽象繪製引擎。
三、元件樹、佈局及樣式
Flutter有三棵樹,作者嫌囉嗦所以只有一棵WidgetTree,好處是實現簡單且方便維持元件例項的狀態。每個介面都由元件樹結構組成。有些元件為佈局類的(eg: Column、Stack等),具備單或多子元件;有些元件為葉子節點(eg: Text、PieChart等),透過設定相應的屬性後直接繪製至畫布。
四、元件狀態
實現元件時如果需要外部狀態驅動,可以定義狀態變數並繫結至元件的相關屬性,這樣當狀態值發生變更時,繫結的元件根據狀態影響進行重新佈局或僅重新繪製。
public class DemoCounter : View
{
private readonly State<int> _counter = 0; //定義狀態
public DemoCounter()
{
Child = new Column
{
Children = new Widget[]
{
new Text(_counter.AsStateOfString()/*繫結至元件*/),
new Button("+") { OnTap = e => _counter.Value+=1/*改變狀態值*/ }
}
};
}
}
五、元件動畫
動畫實現基本照搬Flutter的實現方式,由AnimationController在指定時間段內驅動各Animation的動畫值變化,從而連續改變元件的狀態值。
public class DemoAnimation : View
{
private readonly AnimationController _controller;
private readonly Animation<Offset> _offsetAnimation;
public DemoAnimation()
{
_controller = new AnimationController(1000/*動畫時長*/);
_offsetAnimation = new OffsetTween(new Offset(-1, 0), new Offset(1, 0))
.Animate(_controller); //位移變換並繫結至動畫控制器
Child = new Column
{
Children = new Widget[]
{
new Button("播放動畫") { OnTap = e => _controller.Forward() },
new SlideTransition(_offsetAnimation)
{
Child = new Text("動畫")
}
}
};
}
}
六、後續
力量有限,在此拋磚引玉希望更多感興趣的夥伴加入完善,也希望成為跟華為ArkUI類似的國產UI,對了暫時就叫PixUI吧。