概述
1.Flutter Key
我们平时一定接触过很多的 Widget,比如 Container、Row、Column 等,它们在我们绘制界面的过程中发挥着重要的作用。但是不知道你有没有注意到,在几乎每个 Widget 的构造函数中,都有一个共同的参数,它们通常在参数列表的第一个,那就是 Key.
在Flutter中,Key是不能重复使用的,所以Key一般用来做唯一标识。组件在更新的时候,其状态的保存主要是通过判断组件的类型或者key值是否一致。因此,当各组件的类型不同的时候,类型已经足够用来区分不同的组件了,此时我们可以不必使用key。但是如果同时存在多个同一类型的控件的时候,此时类型已经无法作为区分的条件了,我们就需要使用到key。
Flutter key子类包含 LocalKey 和 GlobalKey 。
局部键(LocalKey):ValueKey、ObjectKey、UniqueKey
ValueKey (值key)把一个值作为key ,
UniqueKey(唯一key)程序生成唯一的Key,当我们不知道如何指定ValueKey的时候就可以使用UniqueKey,
ObjectKey(对象key)把一个对象实例作为key。
全局键(GlobalKey): GlobalKey、GlobalObjectKey
GlobalKey(全局key),GlobalObjectKey(全局Objec key,和ObjectKey有点类似).
没有 Key 会发生什么奇怪现象
如下面例: 定义了一个StatefulWidget的Box,点击Box的时候可以改变Box里面的数字,当我们重新对Box排序的时候Flutter就无法识别到Box的变化了, 这是什么原因呢?
运行后我们发现改变list Widget顺序后,Widget颜色会变化,但是每个Widget里面的文本内容并没有变化,为什么会这样呢?当我们List重新排序后Flutter检测到了Widget的顺序变化,所以重新绘制ListWidget,但是Flutter 发现List Widget 里面的元素没有变化,所以就没有改变Widget里面的内容。
把List 里面的Box的颜色改成一样,这个时候您重新对list进行排序,就很容易理解了。重新排序后虽然执行了setState,但是代码和以前是一样的,所以Flutter不会重构List Widget里面的内容, 也就是Flutter没法通过Box里面传入的参数来识别Box是否改变。如果要让FLutter能识别到List Widget子元素的改变,就需要给每个Box指定一个key。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Widget> list = [ //注意:常量没法改变
//1、可以保存状态 2、可以排序
const Box(
key: ValueKey('1'),
color: Colors.red,
),
Box(
key: UniqueKey(), //唯一值 每次运行的时候会随机生成
color: Colors.yellow,
),
const Box(
key: ObjectKey(Box(color: Colors.blue)),
color: Colors.blue
)
];
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.refresh),
onPressed: (){
setState(() {
list.shuffle(); //shuffle:打乱list元素的顺序
});
},
),
appBar: AppBar(
title: const Text('Title'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: list,
),
),
);
}
}
class Box extends StatefulWidget {
final Color color;
const Box({Key? key, required this.color}):super(key:key);
@override
State<Box> createState() => _BoxState();
}
class _BoxState extends State<Box> {
int _count = 0;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 100,
width: 100,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(widget.color)),
onPressed: () {
setState(() {
_count++;
});
},
child: Text(
"$_count",
style: Theme.of(context).textTheme.headline2,
),
),
);
}
}
2.GlobalKey 获取子组件(3种)
globalKey.currentState: 可以获取子组件的状态,执行子组件的方法,
globalKey.currentWidget:可以获取子组件的属性,
_globalKey.currentContext!.fifindRenderObject():可以获取渲染的属性。
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
//父Widget
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
//1、获取currentState Widget的属性(记住)
var boxState = _globalKey.currentState as _BoxState;
print(boxState._count);
setState(() {
boxState._count++;
});
//调用currentState Widget的方法
boxState.run();
//2、获取子Widget (了解)
var boxWidget = _globalKey.currentWidget as Box;
print(boxWidget.color); //值:MaterialColor(primary value: Color(0xfff44336))
// 3、获取子组件渲染的属性(了解)
var renderBox= _globalKey.currentContext!.findRenderObject() as RenderBox;
print(renderBox.size); //值:Size(100.0, 100.0)
},
),
appBar: AppBar(
title: const Text('Title'),
),
body: Center(
child: Box(key: _globalKey, color: Colors.red),
),
);
}
}
//子Widget
class Box extends StatefulWidget {
final Color color;
const Box({Key? key, required this.color}) : super(key: key);
@override
State<Box> createState() => _BoxState();
}
class _BoxState extends State<Box> {
int _count = 0;
void run() {
print("我是box的run方法");
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: 100,
width: 100,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(widget.color)),
onPressed: () {
setState(() {
_count++;
});
},
child: Text(
"$_count",
style: Theme.of(context).textTheme.headline2,
),
),
);
}
}
3.Widget Tree、Element Tree 和 RenderObject Tree
Flutter应用是由是Widget Tree、Element Tree 和 RenderObject Tree组成
Widget可以理解成一个类,
Element可以理解成Widget的实例,
Widget与Element的关系可以是一对多,一份配置可以创造多个Element实例.
属性 | 描述 |
Widget | Widget就是一个类, 是Element 的配置信息。与Element的关系可以是一对多,一份配置可以创造多个Element实例 |
Element | Widget 的实例化,内部持有Widget和RenderObject。 |
RenderObject | 负责渲染绘制 |
默认情况下面,当Flutter同一个 Widget的大小,顺序变化的时候,FLutter不会改变Widget的state。
最后
以上就是爱笑小猫咪为你收集整理的Flutter组件--LocalKey,GlobalKey以及获取子组件1.Flutter Key 2.GlobalKey 获取子组件(3种)3.Widget Tree、Element Tree 和 RenderObject Tree的全部内容,希望文章能够帮你解决Flutter组件--LocalKey,GlobalKey以及获取子组件1.Flutter Key 2.GlobalKey 获取子组件(3种)3.Widget Tree、Element Tree 和 RenderObject Tree所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复