提出问题
写这篇文章是因为看见了别人写的这一篇文章:https://blog.csdn.net/jike_yangyujing/article/details/103143425?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-7&spm=1001.2101.3001.4242,这篇文章主要讲解了各种Key的使用方法,其中有个例子我非常感兴趣,想要一探究竟。
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.yellow,
),
home: Screen(),
showPerformanceOverlay: true,
);
}
}
class Screen extends StatefulWidget {
@override
_ScreenState createState() => _ScreenState();
}
class _ScreenState extends State<Screen> {
List<Widget> widgets = [
//情形1:stateless
StatelessContainer(),
StatelessContainer(),
// //情形2:stateful
// StatefulContainer(),
// StatefulContainer(),
// //情形3:stateful+key
// StatefulContainer(key: ValueKey(Random().nextInt(1000)),),
// StatefulContainer(key: ValueKey(Random().nextInt(1000)),),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: widgets,
),
),
floatingActionButton: FloatingActionButton(
onPressed: switchWidget,
child: Icon(Icons.undo),
),
);
}
switchWidget() {
setState(() {
widgets.insert(0, widgets.removeAt(1));
});
}
}
//stateless
class StatelessContainer extends StatelessWidget {
final Color randomCol = RandomColor().randomColor();
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: randomCol,
);
}
}
//stateful
class StatefulContainer extends StatefulWidget {
StatefulContainer({Key key}) : super(key: key);
@override
_StatefulContainerState createState() => _StatefulContainerState();
}
class _StatefulContainerState extends State<StatefulContainer> {
final Color randomCol = RandomColor().randomColor();
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: randomCol,
);
}
}
这段代码主要是一个StatefulWidget——Screen,它的子控件主要是一个Row,Row的Children是StatelessContainer /StatefulContainer,而StatelessContainer /StatefulContainer的子控件是一个随机颜色的Container 。点击按钮,预计效果是两个颜色块位置互换。
根据Row的两个Child是StatelessWidget,StatefulWidget,带有Key的StatefulWidget,结果分为三种情形:
1.StatelessWidget:交换成功。
2.StatefulWidget:交换不成功,界面无变化。
3.StatefulWidget+Key:交换成功。
为什么会不一样呢,原文已经给出了解答。本文按照这三种情况,分别对这三个过程进行源码分析。
Element树和RenderObject树的生成
(三种情况是一样的)
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = Re