Flutter StatefulWidget 没有被重建
Posted
技术标签:
【中文标题】Flutter StatefulWidget 没有被重建【英文标题】:Flutter StatefulWidget is not being rebuild 【发布时间】:2021-08-18 06:25:27 【问题描述】:我在使用这段代码时遇到了一些问题.. 我将我的小部件“ComponentsHistoriqueDeployment”移动到带有 initState() 的 statefulwidget,以解决每次小部件时正在重建的焦点问题。 所以实际上数据是第一次获取的,但是当我在搜索栏“Sélectionnez le composant”中录制某些内容或更改 datePicker 时,它不会改变。
我不明白为什么......
这是父母:
class HistoriquePage extends StatefulWidget
final String pageName;
final String namespace;
const HistoriquePage(Key? key, required this.pageName, required this.namespace) : super(key: key);
@override
_HistoriquePageState createState() => _HistoriquePageState();
class _HistoriquePageState extends State<HistoriquePage>
final _debounce = Debounce();
DateTimeRange? dateRange;
String searchedValue = "";
Post? user;
void _sendSearch(String value)
_debounce.run(()
setState(()
searchedValue = value;
);
);
@override
Widget build(BuildContext context) => GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.pageName),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: DateRangeField(
enabled: true,
firstDate: new DateTime(2020),
helpText: 'Sélectionnez un interval de dates',
fieldStartLabelText: 'Date de début',
fieldEndLabelText: 'Date de fin',
fieldStartHintText: 'Début',
fieldEndHintText: 'Fin',
dateFormat: DateFormat('dd/MM/yyyy'),
saveText: 'OK',
decoration: InputDecoration(
prefixIcon: Icon(Icons.date_range, color: Theme.of(context).primaryColor),
hintText: 'Sélectionnez un intervalle de dates',
hintStyle: Theme.of(context).textTheme.headline6,
border: OutlineInputBorder(),
),
onChanged: (value)
setState(()
dateRange = value!;
);
),
),
Container(
padding: EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, color: Theme.of(context).primaryColor),
border: OutlineInputBorder(),
labelText: 'Sélectionnez le composant',
labelStyle: Theme.of(context).textTheme.headline6),
onChanged: _sendSearch),
),
Container(height: MediaQuery.of(context).size.height - 150, child: ComponentsHistoriqueDeployment(searchedValue, dateRange: dateRange))
],
),
),
));
以及应该重建的小部件:
class ComponentsHistoriqueDeployment extends StatefulWidget
ComponentsHistoriqueDeployment(this.searchedValue, this.dateRange, Key? key) : super(key: key);
final String searchedValue;
final DateTimeRange? dateRange;
@override
ComponentsHistoriqueDeploymentState createState() => ComponentsHistoriqueDeploymentState();
class ComponentsHistoriqueDeploymentState extends State<ComponentsHistoriqueDeployment>
List<User>? listOfGroups;
@override
void initState()
getGroupsList();
super.initState();
getGroupsList() async
listOfGroups = await HistoriqueService.fetchHistorique(widget.searchedValue, dateRange: widget.dateRange);
setState(()
listOfGroups = listOfGroups;
);
@override
Widget build(BuildContext context)
return listOfGroups == null
? Center(child: CircularProgressIndicator())
: ListView.separated(
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemCount: listOfGroups!.length,
itemBuilder: (context, index)
return Card(
child: Column(children: [
Padding(
padding: const EdgeInsets.only(top: 8),
child: Badge(
toAnimate: true,
animationDuration: Duration(seconds: 2),
shape: BadgeShape.square,
badgeColor: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(8),
badgeContent: Text(listOfGroups![index].name, style: TextStyle(color: Specific.getWhite, fontSize: 16)),
),
),
_displayMoreInformationOnComponent(listOfGroups, index, context)
]),
);
);
Widget _displayMoreInformationOnComponent(result, index, context)
return Container(
child: ListTile(
title: Text('Tag: ' + result[index].username),
subtitle: Text('Date: ' + result[index].address.street),
leading: Icon(Icons.label),
trailing: Wrap(
spacing: 20,
children: <Widget>[
IconButton(
icon: Icon(Icons.help),
onPressed: () => Dialogs.bottomMaterialDialog(
msgStyle: TextStyle(color: Theme.of(context).textTheme.bodyText2?.color),
msg: 'Tag: ' +
result[index].name +
'\nStatus: ' +
result[index].name +
'\nDernier déploiement: ' +
result[index].name +
'\nType de route: ' +
result[index].name +
'\nDernier commit par: ' +
result[index].name +
'\n',
title: result[index].name,
color: Specific.getOrange,
context: context,
actions: [
IconsButton(
text: "OK",
iconData: Icons.check_circle,
color: Colors.green,
textStyle: TextStyle(color: Specific.getWhite),
iconColor: Specific.getWhite,
onPressed: ()
Navigator.of(context).pop();
,
),
]),
),
],
),
),
);
【问题讨论】:
【参考方案1】:这是预期的行为:initState()
在小部件初始化期间仅被调用一次。即使属性更改了它们的值,State
对象也不会重新创建,因此不会调用 getGroupsList()
。
在这种情况下,我建议您将getGroupsList()
移动到_HistoriquePageState
小部件并在搜索值或日期范围更改时调用它。然后,不要将 searchedValue
和 dateRange
属性传递给 ComponentsHistoriqueDeployment
,而是传递 listOfGroups
值。
这样,您可以确保每次调用 getGroupsList()
并更新 UI。
【讨论】:
谢谢,这真的很有帮助! ,我刚刚添加了一个带有initState
的方法来获取HistoriquePage 上的组。因为如果不是,它只是改变了调用:)
是的,当然,初始加载必须在initState()
中完成,很好。以上是关于Flutter StatefulWidget 没有被重建的主要内容,如果未能解决你的问题,请参考以下文章
Flutter:将传递的参数更改为“StatefulWidget”
Flutter 中的 statefulWidget 中的屏幕未更新
了解 Flutter 中 StatefulWidget 的使用