
Flet 扩展项目模板指南从flet create --template extension到跨平台自定义控件【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet本文以 Flet 官方仓库中「扩展Extension项目模板」所生成的 README.md 为骨架系统讲解如何把任意 Flutter 包包装成 Flet 自定义控件Control/Service包括项目结构、Python 与 Dart 双端如何分工、依赖声明、flet debug与flet build两种运行方式以及如何借助模板中的示例与源码把控件真正跑起来。读完本文你将掌握一个 Flet 扩展从创建、安装、构建到跨平台运行的完整闭环。扩展项目模板是什么Flet 是一个「仅用 Python 就能构建实时 Web、移动与桌面应用」的框架其渲染层依赖 Flutter。当一个功能不在 Flet 内置控件中、又希望复用 Flutter 生态里丰富的第三方包时Flet 提供了官方扩展机制。仓库中的 sdk/python/templates/app/extension 目录正是这套机制的项目脚手架通过 cookiecutter.json 定义占位变量最终生成一个名为{{cookiecutter.project_name}}的 Flet extension 项目project_name扩展包名如flet-spinkitproject_name_underscore由project_name自动转换-替换为_用作 Python 与 Dart 的模块名control_name由项目名派生出的控件类名大写驼峰如FletSpinkitflet_version扩展所依赖的 Flet 最低版本description对扩展的一句话描述会渲染进生成的 README。创建方式在文档 website/docs/extend/user-extensions.md 中有完整说明flet create --template extension --project-name flet-spinkit生成后的项目即为一个标准的 Flet extension其 README 由模板渲染正文开头即声明{{cookiecutter.project_name}}Flet extension并可选附带{{cookiecutter.description}}描述。一个扩展的两个侧面Python 控件与 Flutter Widget模板 README 强调了一个核心事实Flet 扩展有两侧——Python 侧的控件/服务以及背后的原生 Flutter/Dart Widget。以模板生成的{{cookiecutter.control_name}}控件为例两侧代码分工如下。Python 侧声明控件协议src/{{cookiecutter.project_name_underscore}}/{{cookiecutter.project_name_underscore}}.py 定义了控件的 Python 外观from enum import Enum from typing import Any, Optional import flet as ft ft.control({{cookiecutter.control_name}}) class {{cookiecutter.control_name}}(ft.LayoutControl): {{cookiecutter.control_name}} Control description. value: str要点ft.control({{cookiecutter.control_name}})装饰器把控件类注册到 Flet字符串参数即控件类型名必须与 Dart 侧switch (control.type)的分支字符串完全一致控件继承ft.LayoutControl表示它作为布局型控件参与页面树value: str是以类型注解形式声明的属性Flet 会据此完成属性校验与序列化模板仅给出一个最小示例实际开发时可在这里扩充任意属性、事件on_*与行为。模块的公开入口在 src/{{cookiecutter.project_name_underscore}}/init.py它把控件类导出到包顶层from {{cookiecutter.project_name_underscore}}.{{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}}Dart 侧注册与渲染Flutter 包位于 src/flutter/{{cookiecutter.project_name_underscore}}其中 lib/{{cookiecutter.project_name_underscore}}.dart 作为库入口导出扩展注册类library {{cookiecutter.project_name_underscore}}; export src/extension.dart show Extension;lib/src/extension.dart 继承FletExtension把 Python 侧传入的控件类型名映射为真正的 Flutter Widgetimport package:flet/flet.dart; import package:flutter/widgets.dart; import {{cookiecutter.project_name_underscore}}.dart; class Extension extends FletExtension { override Widget? createWidget(Key? key, Control control) { switch (control.type) { case {{cookiecutter.control_name}}: return {{cookiecutter.control_name}}Control(control: control); default: return null; } } }而 lib/src/{{cookiecutter.project_name_underscore}}.dart 是控件真正的渲染实现——模板中它只是读取value属性并渲染成一个Textclass {{cookiecutter.control_name}}Control extends StatelessWidget { final Control control; const {{cookiecutter.control_name}}Control({super.key, required this.control}); override Widget build(BuildContext context) { String text control.getString(value, )!; Widget myControl Text(text); return LayoutControl(control: control, child: myControl); } }这正是你后续「魔改」的起点把Text(text)替换成任何第三方 Flutter 包里的 Widget并把新的构造参数通过control.getXxx(...)从 Python 侧读取即可。Flutter 包的依赖声明在 pubspec.yaml其中flet: ^{{cookiecutter.flet_version}}保证了与 Flet 客户端版本对齐。把扩展装进你的 Flet 项目模板 README 提供了两种安装方式均以pyproject.toml的dependencies声明。从 Git 安装开发/私有分发dependencies [ {{cookiecutter.project_name}} githttps://github.com/MY_GITHUB_ACCOUNT/{{cookiecutter.project_name}}, flet{{cookiecutter.flet_version}}, ]适用于扩展尚未发布到 PyPI、或需要直接从仓库源码安装的场景。安装时请把MY_GITHUB_ACCOUNT替换为你的实际仓库账号。从 PyPI 安装正式发布dependencies [ {{cookiecutter.project_name}}, flet{{cookiecutter.flet_version}}, ]两种方式都显式声明了flet{{cookiecutter.flet_version}}确保运行环境中的 Flet 不低于扩展开发时的基线版本。模板自带的打包与依赖配置模板生成的 pyproject.toml 已经为发布做好了准备几个关键点值得注意[tool.setuptools.package-data]中flutter.{{cookiecutter.project_name_underscore} [**/*]保证 Flutter/Dart 源码随 Python 包一起分发requires-python 3.10最低 Python 版本要求dev 依赖组内置mkdocs、mkdocs-material与mkdocstrings[python]配合仓库中 mkdocs.yml 与 docs 目录可直接用 mkdocstrings 从 Python 源码自动生成 API 文档项目元数据中的 Homepage、Documentation、Repository、Issues 等链接在生成后需替换为你的真实地址。示例应用如何引用本地扩展模板在 examples/{{cookiecutter.project_name_underscore}}_example/pyproject.toml 中给出了示例应用引用扩展的两种机制[tool.flet.dev_packages] {{cookiecutter.project_name}} ../.. # relative path [tool.uv.sources] {{cookiecutter.project_name}} { path ../../, editable true }[tool.flet.dev_packages]让 Flet 构建系统在打包客户端时从../..扩展项目根目录找到 Flutter 源码并编译进去[tool.uv.sources]则以 editable可编辑方式安装 Python 包方便对扩展 Python 代码的热更新调试[tool.flet]段配置了org反域名记法的组织名与项目名共同构成 iOS/Android 的 bundle ID、product桌面窗口标题/移动端图标下显示名、company与copyright该示例还按平台区分 dev 依赖flet-desktop或 Linux 下的flet-desktop-light与flet-web。示例应用本体在 examples/{{cookiecutter.project_name_underscore}}_example/src/main.py展示了控件的最基本用法import flet as ft from {{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}} def main(page: ft.Page): page.vertical_alignment ft.MainAxisAlignment.CENTER page.horizontal_alignment ft.CrossAxisAlignment.CENTER page.add( ft.Container( height150, width300, alignmentft.Alignment.CENTER, bgcolorft.Colors.PURPLE_200, content{{cookiecutter.control_name}}( tooltipMy new {{cookiecutter.control_name}} Control tooltip, valueMy new {{cookiecutter.control_name}} Flet Control, ), ), ) ft.run(main)同样的示例也直接写进了扩展自身的 docs/index.md作为文档首页的 Introduction 内容。为什么不能直接flet run预编译客户端不含扩展模板 README 特别提醒了一个关键限制普通flet run所用的预编译客户端prebuilt client不包含你的扩展。扩展的原生代码必须编译进 Flet 客户端控件才能渲染。因此运行方式分两类方式一flet debug—— 覆盖全平台flet debug会编译扩展并在你选择的目标上启动应用对桌面与 Web 无需连接设备对移动端则需先连接设备或模拟器flet debug macos # desktop web: no device needed flet debug android -d device-id # mobile: connect a device/emulator firstiOS 与 Android 需要-d device-id指定目标设备可用flet debug --show-devices列出已连接设备该命令是移动端与 Web 的首选方式也是最简单的选项对Python 代码的修改在下次运行flet debug时即被拾取无需重新编译。方式二flet buildflet run—— 桌面快速热重载桌面端Windows、macOS、Linux可以先一次性构建包含扩展的自定义客户端之后用flet run进入快速热重载循环flet build macos # or: flet build windows / flet build linux flet run # run from the folder where build/ was created, so it reuses that clientflet run会自动检测build/platform/下的客户端并复用Python 编辑即刻热重载只有当扩展的Dart代码发生变更时才需要重新执行flet build官方扩展指南 website/docs/extend/user-extensions.md 中演示的正是这一工作流首次flet build macos -v构建 → 修改main.py后直接flet run→ 修改 Flutter 包后再flet build macos -v。这一「Python 即时热更、Dart 需重建」的区分正是由扩展双端架构决定的Python 控件只负责属性协议与业务逻辑Flutter Widget 才是需要编译进客户端的渲染代码。控件的使用与文档化在应用中使用扩展安装完成后在应用中导入并使用控件import flet as ft from {{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}} def main(page: ft.Page): ... page.add({{cookiecutter.control_name}}(value..., tooltip...))模板控件目前支持value字符串内容与tooltip悬浮提示两个属性它们分别经 Dart 侧control.getString(value, )读取、由LayoutControl基类处理。开发新属性时只需在 Python 类注解中新增字段并在 Dart 侧用control.getXxx(属性名, 默认值)读取即可。平台支持矩阵模板 README 中的平台支持表用 ✅/❌ 维护PlatformiOSAndroidWebWindowsmacOSLinuxSupported✅✅✅✅✅✅默认全部勾选实际发布时应按真实测试结果更新——例如若某个第三方 Flutter 包不支持 Web就应把 Web 列改为 ❌。编写文档模板 README 同时预留了文档章节可在Documentation一节直接书写或链接到独立文档站点README 模板中留的是https://MY_GITHUB_ACCOUNT.github.io/...占位。模板已自带 mkdocs 骨架mkdocs.yml 使用 material 主题与 mkdocstrings 插件并在 docs/index.md 中给出控件类文档页与示例代码的挂载方式安装mkdocs后运行mkdocs serve即可本地预览。从模板到真实扩展的改造路径综合模板源码与官方指南 website/docs/extend/user-extensions.md一个扩展的典型改造流程是生成骨架flet create --template extension --project-name flet-spinkit声明依赖在src/flutter/pkg/下执行flutter pub add third-party-package把第三方 Flutter 包加进 pubspec实现 Widget在lib/src/pkg.dart中把模板的Text(text)替换为第三方 Widget并用control.getString(...)/control.getBool(...)/control.getNumeric(...)等读取 Python 侧传入的属性扩充 Python 控件在 Python 类中新增类型注解属性与事件保持控件协议与 Dart 侧读取逻辑一一对应构建验证在示例应用目录执行flet build platform -v-v输出详细日志便于排查迭代改 Python 用flet run热重载改 Dart 则重新flet build移动/Web 场景用flet debug发布更新 README 中的平台支持矩阵、链接与文档再发布到 PyPI 或 Git 仓库。结语Flet 扩展模板把「Flutter 包 → Flet 控件」的整个工程化流程固化成了标准骨架Python 侧负责控件协议Dart 侧负责渲染注册pyproject.toml负责打包与 dev 依赖示例应用与 mkdocs 文档开箱即用。理解「预编译客户端不含扩展」这一限制后flet debug全平台与flet buildflet run桌面热重载两种运行方式即可覆盖你的全部开发场景。从 模板 README 出发配合 模板源码 与 官方扩展指南你就能按同样的路径把任意 Flutter 生态能力带入纯 Python 的 Flet 应用。【免费下载链接】fletBuild realtime web, mobile and desktop apps in Python only. No frontend experience required.项目地址: https://gitcode.com/gh_mirrors/fl/flet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考