GitHub: https://github.com/yangyuan/flut/ PYPI: https://pypi.org/project/flut/
用法
安装:pip install flut
// 正常用 Dart 写 Flutter 是这样
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Text('Hello'),
)
# 在 Python 用 Flut 就是这样
Container(
padding=EdgeInsets.all(16),
decoration=BoxDecoration(
color=Colors.blue,
borderRadius=BorderRadius.circular(8),
),
child=Text('Hello'),
)
原始的 Flutter contract ,执行时被映射到 flutter 真实的代码。所以是真实的 Flutter 在运行。
这是针对桌面的 SDK ,目标不是一个发布产品的 SDK 而是一个快速做点小桌面应用的包。
比如:学生的大作业,科研做点小 demo ;需要 Python 又想要有个不需要配置的 UI ,这样的场景。再比如我自己用这个做了个本地桌面 Agent ,我自己觉得比命令行好用就行。
- 设计上,原则是原生 1:1 对应,Python 这边写的啥样,就在 Flutter 这里 1:1 照搬执行。
- 异步集成设计上基本遵照了 Libuv ,Electron ,Chromium 的做法,不敢说没 bug, 但设计绝对是产品级的。
- 性能上,FFI 期间的确需要序列化,会带来理论上的损失。实际执行上,只要设备不太差,性能损失和事件延时是无感的。我 4 年老本上维持 120hz 动画和无延时拖拽,Catalog 里有一些样例。
- 内存生命周期上,以及 flutter 覆盖度上,还有很大改进空间。
自己画的图标:
catalog app https://github.com/yangyuan/flut/tree/master/examples/catalog 做的比较粗糙,但主要能看常见支持的功能。
一个简单但完整能跑的例子:
from flut import run_app
from flut.flutter.widgets import StatelessWidget, StatefulWidget, State, Text, Center, Column, Icon
from flut.flutter.material import MaterialApp, Scaffold, AppBar, FloatingActionButton, Icons, ThemeData, ColorScheme, Colors, Theme
from flut.flutter.rendering import MainAxisAlignment
class MyApp(StatelessWidget):
def build(self, context):
return MaterialApp(
title="Flut Demo",
theme=ThemeData(
colorScheme=ColorScheme.fromSeed(seedColor=Colors.deepPurple),
),
home=MyHomePage(title="Flut Demo Home Page"),
)
class MyHomePage(StatefulWidget):
def __init__(self, title):
super().__init__()
self.title = title
def createState(self):
return _MyHomePageState()
class _MyHomePageState(State[MyHomePage]):
def initState(self):
self._counter = 0
def _incrementCounter(self):
def _update():
self._counter += 1
self.setState(_update)
def build(self, context):
return Scaffold(
appBar=AppBar(
title=Text(self.widget.title),
backgroundColor=Theme.of(context).colorScheme.inversePrimary,
),
body=Center(
child=Column(
mainAxisAlignment=MainAxisAlignment.center,
children=[
Text("You have pushed the button this many times:"),
Text(
f"{self._counter}",
style=Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton=FloatingActionButton(
onPressed=self._incrementCounter,
tooltip="Increment",
child=Icon(Icons.add),
),
)
if __name__ == "__main__":
run_app(MyApp())