← 開發日常

跳過 Widget 直接渲染畫面

大家都知道 Flutter 是一套 UI 框架,透過 dart:ui 與底層 API 互動,最終呈現在手機螢幕上或接收點擊事件。使用的時候,都是透過已經定義好的 Widget 決定畫面,並不會直接與 dart:ui 互動。但是實際上,我們也是可以跳過 Widget,直接操作 dart:ui 的 API 來幫我們畫出我們想樣的畫面

Article image

而 Widget、 Element、RenderObject 等等我們比較常互動的物件,則更多是讓我們更方面的使用 Flutter,讓我們可以輕鬆在畫面畫出想要的結果,而不用自己一筆一劃決定,也不需要自己決定何時重新渲染畫面。

畫一個圓

下面這段代碼直接操作 Picture、Scene、Window ...等物件,在畫面上畫出一個藍色的原型。

  1. 一開始創建了 PictureRecorder 與 Canvas,並利用 Paint 在 Canvas 上畫出一個圓,與在 CustomPainter 畫圖的做法相當類似。
  2. 當畫完之後,呼叫 PictureRecording.endRecording(),並取得一張 Picture
  3. 接著我們就能把這張 Picture 透過 SceneBuilder 放進 Scene 中
  4. 最後用 window 來這一幀的畫面
dart
void main() {
	PictureRecorder recorder = PictureRecorder();
  Canvas canvas = Canvas(recorder);

  Paint circlePaint = Paint();
  circlePaint.color = Colors.blue;
  canvas.drawCircle(Offset(400, 400), 300, circlePaint);

  Picture picture = recorder.endRecording();

  SceneBuilder sceneBuilder = SceneBuilder();
  sceneBuilder.addPicture(Offset(0, 0), picture);

  Scene scene = sceneBuilder.build();
  window.onDrawFrame = () {
    window.render(scene);
  };
  window.scheduleFrame();
}

當執行上面這段代碼後,我們在畫面上看到一個藍色圓形,向下方左圖一樣。同樣的方法也可以用來畫出向下方右圖那樣的複雜圖形。

小結

雖然我們可以直接使用 dart:ui 在畫面上直接作畫,但實際上在絕大多數的狀況下不會這麼做,目前我自己也想不到一樣狀況會需要這樣做。畢竟除了繪製,Flutter 實際上還做了許許多多事,不管是狀態管理或者是效能優化,透過 Widget、Element 和 RenderObject 去操作還是推薦的做法。

參考