在Flutter中,当widget树中的一个widget需要更新时,Flutter会根据以下三个因素来决定是否更新widget:

Widget的Type是否相同

当widget树中的一个widget需要更新时,Flutter会首先检查widget的Type是否相同。如果新的widget和旧的widget的Type不同,那么Flutter将会创建一个新的widget,并将其插入到widget树中。

例如,假设我们有一个Text widget,它的文本内容随着时间而变化:

Text(

_getTime(),

style: TextStyle(fontSize: 16.0),

),

String _getTime() {

var now = DateTime.now();

return '${now.hour}:${now.minute}:${now.second}';

}

在上述代码中,我们使用一个函数_getTime来获取当前时间,并将其作为Text widget的文本内容。每秒钟,我们会调用setState来通知Flutter更新widget的状态,从而更新文本内容。

在每次更新时,Flutter会检查新的Text widget和旧的Text widget的Type是否相同。由于它们的Type相同,Flutter将只更新它们的属性,而不会创建新的widget。这可以提高应用程序的性能,并确保widget的正确更新。

Widget的Key是否相同

当widget树中的一个widget需要更新时,Flutter会其次检查widget的Key是否相同。如果新的widget和旧的widget的Key相同,那么Flutter将会重用旧的widget,并仅更新它的属性。否则,Flutter将会创建一个新的widget,并将其插入到widget树中。

Row(

children: [

ElevatedButton(

onPressed: () {},

child: Text('Button 1'),

),

ElevatedButton(

onPressed: () {},

child: Text('Button 2'),

),

],

)

如果我们在应用程序中多次使用这个Row,但没有为它们指定Key,则当我们更新其中一个按钮的属性时,Flutter会重新构建整个Row,这会降低性能。 相比之下,当我们为widget指定带UniqueKey的Key时,Flutter将能够区分不同的widget,并且只更新发生变化的部分。这可以提高应用程序的性能,并确保widget的正确更新。 假设我们有一个表单,包含多个文本输入框。我们希望能够检测表单中任何一个输入框的值是否发生了变化,以便在用户试图离开表单时提示用户保存更改。我们可以为每个输入框都指定一个唯一的Key,这样当用户修改任何一个输入框时,Flutter将只更新它发生了变化的输入框,而不会更新其他输入框。

class MyForm extends StatefulWidget {

@override

_MyFormState createState() => _MyFormState();

}

class _MyFormState extends State {

final _formKey = GlobalKey();

final _nameKey = UniqueKey();

final _emailKey = UniqueKey();

final _phoneKey = UniqueKey();

String _name;

String _email;

String _phone;

@override

Widget build(BuildContext context) {

return Form(

key: _formKey,

child: Column(

children: [

TextFormField(

key: _nameKey,

initialValue: _name,

decoration: InputDecoration(labelText: 'Name'),

onChanged: (value) => setState(() => _name = value),

),

TextFormField(

key: _emailKey,

initialValue: _email,

decoration: InputDecoration(labelText: 'Email'),

onChanged: (value) => setState(() => _email = value),

),

TextFormField(

key: _phoneKey,

initialValue: _phone,

decoration: InputDecoration(labelText: 'Phone'),

onChanged: (value) => setState(() => _phone = value),

),

ElevatedButton(

onPressed: () {

if (_formKey.currentState.validate()) {

// 不会每次点击,输入框里面的值都消失了

}

},

child: Text('Save'),

),

],

),

);

}

}

在上述代码中,我们为每个输入框都指定了一个唯一的Key,以确保它们能够正确地重用并仅更新它们发生变化的部分。我们还将每个输入框的值保存在相应的私有变量中,并使用setState来通知Flutter更新它们的值。

Widget的属性是否相同

当widget的Type和Key都相同时,Flutter将只更新widget的属性。以下是一个示例,演示了如何使用Key和Type来优化一个包含多个列表项的列表的性能。

假设我们有一个列表,其中包含多个列表项。我们希望能够检测列表中任何一个列表项的状态是否发生了变化,以便在需要时更新列表项的显示。我们可以为每个列表项都指定一个唯一的Key,并确保它们的Type不变,这样当列表项的状态发生变化时,Flutter将只更新发生了变化的列表项,而不会更新其他列表项。

class MyList extends StatefulWidget {

@override

_MyListState createState() => _MyListState();

}

class _MyListState extends State {

final _items = List.generate(100, (index) => 'Item $index');

@override

Widget build(BuildContext context) {

return ListView.builder(

itemCount: _items.length,

itemBuilder: (context, index) {

final item = _items[index];

return MyListItem(

key: ValueKey(item),

title: item,

);

},

);

}

}

class MyListItem extends StatefulWidget {

final String title;

MyListItem({Key key, this.title}) : super(key: key);

@override

_MyListItemState createState() => _MyListItemState();

}

class _MyListItemState extends State {

bool _isChecked = false;

@override

Widget build(BuildContext context) {

return ListTile(

title: Text(widget.title),

leading: Checkbox(

value: _isChecked,

// 点击之后不会刷新整个列表

onChanged: (value) => setState(() => _isChecked = value),

),

);

}

}

在上述代码中,我们使用ListView.builder来构建列表,并为每个列表项都指定一个唯一的Key。当构建列表项时,我们使用MyListItem widget来包装它们,并将其title作为属性传递。在MyListItem widget中,我们使用Checkbox来表示列表项的状态,并将其值保存在私有变量_isChecked中。通过使用Key和Type,我们可以确保Flutter只更新发生了变化的列表项,并提高应用程序的性能和响应性能。

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: