我已经意识到可以使用普通函数创建小部件而不是子类化StatelessWidget。一个例子是这样的:
Widget function({ String title, VoidCallback callback }) {
return GestureDetector(
onTap: callback,
child: // some widget
);
}
这很有趣,因为它需要的代码远远少于完整的类。例:
class SomeWidget extends StatelessWidget {
final VoidCallback callback;
final String title;
const SomeWidget({Key key, this.callback, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: callback,
child: // some widget
);
}
}
所以我一直在想:除了创建小部件的函数和类之间的语法之外还有什么区别吗?使用函数是一个好习惯吗?
TL; DR:永远不要使用类上的函数来制作可重用的小部件树。总是将这些提取到StatelessWidget中。
使用函数而不是类之间存在巨大差异,即:框架不知道函数,但可以看到类。
考虑以下“小部件”功能:
Widget functionWidget({ Widget child}) {
return Container(child: child);
}
用这种方式:
functionWidget(
child: functionWidget(),
);
它等同于类:
class ClassWidget extends StatelessWidget {
final Widget child;
const ClassWidget({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: child,
);
}
}
像那样使用:
new ClassWidget(
child: new ClassWidget(),
);
在纸面上,两者似乎做了完全相同的事情:创建2个Container
,其中一个嵌套到另一个中。但现实略有不同。
在函数的情况下,生成的小部件树如下所示:
Container
Container
使用类时,窗口小部件树是:
ClassWidget
Container
ClassWidget
Container
这非常重要,因为它从根本上改变了更新窗口小部件时框架的行为方式。以下是差异的精选列表:
结论应该很清楚:
不要使用函数来创建小部件。
过去两天我一直在研究这个问题。我得出以下结论:将应用程序的各个部分分解为函数是可以的。这些函数返回StatelessWidget
是理想的,因此可以进行优化,例如制作StatelessWidget
const
,因此如果不需要则不会重建。例如,这段代码完全有效:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
++_counter;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
const MyWidgetClass(key: const Key('const')),
MyWidgetClass(key: Key('non-const')),
_buildSomeWidgets(_counter),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _buildSomeWidgets(int val) {
print('${DateTime.now()} Rebuild _buildSomeWidgets');
return const MyWidgetClass(key: Key('function'));
// This is bad, because it would rebuild this every time
// return Container(
// child: Text("hi"),
// );
}
}
class MyWidgetClass extends StatelessWidget {
const MyWidgetClass({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
print('${DateTime.now()} Rebuild MyWidgetClass $key');
return Container(
child: Text("hi"),
);
}
}
函数的使用完全没有问题,因为它返回了const StatelessWidget
。如果我错了,请纠正我。
当您调用Flutter小部件时,请确保使用const关键字。例如const MyListWidget();