[Flutter翻譯]Flutter without Flutter

原文地址:medium.com/icnh/flutte…canvas

原文做者:medium.com/@eibaan_546…windows

發佈時間:2020年5月2日 - 3分鐘閱讀框架

這是一個實驗。讓咱們在不使用Flutter框架的狀況下,建立在移動設備上顯示一些東西所需的最小代碼。dom

不美不美,自成一派ide

Flutter是一個高級GUI框架,它使用dart:uiSkia引擎的一個抽象)來實際顯示一些東西,並與這些東西所顯示的平臺進行交互。固然,咱們本身也能夠直接使用這個低級別的dart:ui庫。函數

設置

讓咱們建立一個新的Flutter項目。ui

$ flutter create flutter_without_flutter
複製代碼

而後用這段代碼替換lib/main.dartspa

import ‘dart:ui’;
void main() {
 window.onBeginFrame = beginFrame;
 window.scheduleFrame();
}
void beginFrame(Duration duration) {
}
複製代碼

解釋:咱們用window單例註冊一個名爲beginFrame的全局函數,而後要求圖形引擎對該函數進行回調。它應該準備並最終繪製一個幀,也就是在設備屏幕上顯示一些東西。翻譯

繪製一些東西

由於我習慣用邏輯單位而不是物理像素來工做,因此 beginFrame 的第一步是將設備的物理屏幕尺寸轉換爲更熟悉的數值。code

void beginFame(Duration duration) {
 final pixelRatio = window.devicePixelRatio;
 final size = window.physicalSize / pixelRatio;
 final physicalBounds = Offset.zero & size * pixelRatio;
 …
複製代碼

下一步是設置一個使用邏輯單元的Canvas

final recorder = PictureRecorder();
 final canvas = Canvas(recorder, physicalBounds);
 canvas.scale(pixelRatio, pixelRatio);
 …
複製代碼

而後讓咱們用紅色的顏料畫一個圓圈。

final paint = Paint()..color = Color(0xFFF44336);
 final center = size.center(Offset.zero);
 canvas.drawCircle(center, size.shortestSide / 4, paint);
 …
複製代碼

最後一步是將調用Canvas方法建立的錄音,用它來構建一個所謂的場景,而後由windows單例渲染。

final picture = recorder.endRecording();
 final sceneBuilder = SceneBuilder()
 ..pushClipRect(physicalBounds)
 ..addPicture(Offset.zero, picture)
 ..pop();
 window.render(sceneBuilder.build());
}
複製代碼

順便說一下,一般的Flutter項目的即時熱代碼重載仍然有效,這就是爲何它可能會有用,使用這種設置來建立低水平的圖形應用程序,例如2D遊戲。

移動起來

爲了移動圓圈並使其在屏幕上彈跳,咱們將把它的中心點存儲在一個全局變量(稱爲center)中,把它的速度存儲在另外一個全局變量(稱爲velocity)中,每次調用beginFrame時修改這些變量,而後在beginFrame函數結束時使用scheduleFrame請求另外一次繪製操做。

下面是相關的修改。

Offset center;
Offset velocity;
void beginFrame(Duration duration) {
 …
 canvas.scale(pixelRatio, pixelRatio);
final radius = size.shortestSide / 4;
 if (center == null) {
 center = size.center(Offset.zero);
 velocity = Offset(3, 5);
 } else {
 if (center.dx < radius || center.dx > size.width — radius)
 velocity = velocity.scale(-1, 1);
 if (center.dy < radius || center.dy > size.height — radius)
 velocity = velocity.scale(1, -1);
 center += velocity;
 }
final paint = Paint()..color = Color(0xFFF44336);
 canvas.drawCircle(center, radius, paint);
…
window.scheduleFrame();
}
複製代碼

由於咱們沒法控制beginFrame函數的調度頻率,因此咱們可能應該利用傳遞的duration,並將圓的速度與傳遞的時間綁定。爲了計算調用之間所通過的時間,咱們引入另外一個全局變量,叫作lastDuration

Duration lastDuration;
void beginFrame(Duration duration) {
 …
 if (center == null) {
 …
 } else {
 …
 final delta = (duration — lastDuration).inMilliseconds / 1000;
 center += velocity * delta;
 }
 lastDuration = duration;
…
複製代碼

若是你保持應用程序的運行,只是修改了soure代碼,圓圈應該已經開始移動,就像魔法同樣。

對觸摸的反應

最後但一樣重要的是,讓咱們在每次點擊屏幕時改變速度。爲了檢測觸摸,咱們須要添加另外一個回調函數onPointerDataPacket。這個函數接收一個PointerData對象的列表,這些對象描述了觸摸向下、觸摸移動和觸摸向上的事件。不過咱們只對 PointerChange.up 類型的事件感興趣。

這裏是新的主函數。

void main() {
 window.onBeginFrame = beginFrame;
 window.onPointerDataPacket = pointerDataPacket;
 window.scheduleFrame();
}
複製代碼

這裏是新的回調函數。

void pointerDataPacket(PointerDataPacket packet) {
 for (final data in packet.data) {
 if (data.change == PointerChange.up) {
 velocity = Offset.fromDirection(
 _random.nextDouble() * pi * 2,
 _random.nextDouble() * 800400,
 );
 }
 }
}
final _random = Random();
複製代碼

利用這個基礎,你應該能夠從頭開始建立本身的相似Flutter的GUI框架。

我將此做爲一個練習留給讀者:-)


經過www.DeepL.com/Translator(免費版)翻譯

相關文章
相關標籤/搜索