[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(免费版)翻译

相关文章
相关标签/搜索