原文作者:ookamikb.medium.com/
发布时间:4月15日-4分钟阅读
这篇文章是关于推广我的Flutter库,用于展示孤立的小部件和屏幕。就像React世界里的Storybook一样。实际上,它甚至被命名为storybook_flutter。
为什么你需要它?
首先,为了加快UI开发速度。是的,Flutter有一个 "热重载",可以让UI开发非常流畅,但如果你要开发的widget在应用屏幕深处的某个地方呢?如果只有在某些特定条件下才能看到呢?除此之外,热重载也不是在所有情况下都能用。因此,隔离小部件,使其成为一个单独的故事,并与这个故事一起工作的可能性是非常有用的。
第二,展示你的widget和屏幕。例如,我们为Flutter实现了自己的设计库,我们希望在文档中集成一个带有widget的交互式沙盒。尤其是现在,Flutter for Web已经进入稳定通道。
第三,从一开始就有一个功能要求:用每一个可能的widget参数组合自动生成黄金测试。我觉得这个想法挺有意思的,我希望将来能增加这个功能。
你不能直接使用一些现有的库吗?
也许可以,是的。但是,目前在社区库中还没有明确的领导者。另外,你也不能把NIH综合症从柜台上拿下来:) 除此以外,我希望能够尽快添加我们需要的功能。
它是什么样子的呢?
有点像这样。
是的,不是艺术作品,但这不是现在的首要任务,而且我的设计能力也不高... 除此之外,我还在试验按钮和工具栏的位置,所以目前没有必要去打磨视觉风格。
你能用它做什么?
- 故事导航,可选择按章节分组。
- 小工具的旋钮(可自定义参数)。
- 明暗主题切换。
- 故事的全屏模式,没有任何UI元素--可以用于网络,例如,将故事嵌入到iframe中。
- 自定义。
- 设备框架(感谢device_frame包)。
- 插件支持。
如何使用它?
将依赖关系添加到 pubspec.yaml 文件中。
storybook_flutter: ^0.5.0
创建故事 一个最简单的例子是
import 'package:flutter/material.dart';
import 'package:storybook_flutter/storybook_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Storybook(
children: [
Story.simple(
name: 'Button',
child: ElevatedButton(
onPressed: () {},
child: const Text('Push me'),
),
),
],
);
}
运行项目,然后就可以了
让我们添加一些旋钮 我们需要做的就是用一个默认的简单构造函数(simpleconstructor)代替,并且使用 builderinstead 而不是 child。
再次运行构建程序 现在更好了。
Story(
name: 'Button',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
按章节对故事进行分组,就像添加章节参数一样简单。
所有具有相同章节值的故事都会被自动分组。
Story(
name: 'Button',
section: 'Buttons',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
如何自定义?
每个故事都有padding和颜色参数,控制故事的padding和背景颜色。
Story(
name: 'Button',
section: 'Buttons',
padding: const EdgeInsets.all(8),
background: Colors.red,
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
但这太简单了 更多有趣的事情可以通过wrapperBuilder参数来完成。它允许用一个自定义的widget来包装故事。
Story(
name: 'Button',
section: 'Buttons',
wrapperBuilder: (context, story, child) => Container(
decoration: BoxDecoration(border: Border.all()),
margin: const EdgeInsets.all(16),
child: Center(child: child),
),
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
这个构件可以作为storybook中storyWrapperBuilder参数的一个值传递给我们。在这种情况下,每个故事都会被这个widget包装(当然,你仍然可以用一个故事的wrapperBuilder单独覆盖它)。
我们需要更多的自定义功能!
如果构建器、包装器和参数还不够,你可以拿CustomStorybook来自己做一切。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final decoration = BoxDecoration(
border: Border(
right: BorderSide(color: Theme.of(context).dividerColor),
left: BorderSide(color: Theme.of(context).dividerColor),
),
color: Theme.of(context).cardColor,
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: CustomStorybook(
builder: (context) => Row(
children: [
Container(
width: 200,
decoration: decoration,
child: const Contents(),
),
const Expanded(child: CurrentStory()),
Container(
width: 200,
decoration: decoration,
child: const KnobPanel(),
),
],
),
children: [
Story(
name: 'Button',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
)
],
),
),
);
}
}
你仍然可以使用内置的widget: Contents, CurrentStory和KnobPanel (我打赌你能猜到它们的作用). 我们将在这里得到一些最小化的结果。
CustomStorybook的一个可能的用例是这个插件,它将Storybook添加到另一个包中,device_preview,支持内容和旋钮面板。有了它,你可以实现这样的东西。
那插件呢?
最新版本增加了对插件和第一方插件DeviceFramePlugin的支持。
插件允许重写故事的渲染方式,也可以在面板上添加自定义设置。不过创建插件是另一篇文章的主题。
支持哪些平台?
好吧,引擎盖下没有特殊的魔法,所以理论上它应该可以在Flutter支持的所有平台上工作。我已经在Android、iOS、web和macOS上测试过了。
有什么路线图吗?
首先,稳定插件API,思考应该提供哪些开箱即用的插件(当然也要开发)。
之后,我想我会像开头提到的那样,研究一下黄金测试生成。
就这样吧。欢迎大家提出任何意见、功能要求和bug报告(以及点赞和星星)。
原文发表于:developers.mews.com 2021年4月15日。