ValueNotifier:在页面构建完成抛出异常之前更新小部件的文本
ValueNotifier: update widget's text before page's build completes throws exceptions
我在构建页面时尝试计算百分比并将其作为文本设置到文本小部件中。在我的应用程序中,我有一个带有 ListTile 的设置页面,它通过点击将用户带到一个新页面。在新页面 (percentage_settings_page.dart) 中,我从我的 SQLITE 数据库中读取数据,其中包含一些使用 FutureBuilder<List<User>>
和 ListView.builder()
.
的用户
在构建包含每个用户的名称和百分比的列表视图时,我需要计算剩余百分比,这是通过从 100 中减去用户百分比的总和得出的,并将其设置在循环指示器中。我正在尝试使用 ValueNotifier
来实现这一点。页面是这样的:
How it is: displaying 100
How it should be
percentage_settings_page.dart
:
class _PercentageSettingsPageState extends State<PercentageSettingsPage> {
/* other variables */
final ValueNotifier<double> _myPercentage = ValueNotifier<double>(100);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Divide percentage'),
leading: BackButton(
onPressed: () async => Navigator.pop(context),
),
),
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 20),
child: Align(
alignment: Alignment.topCenter,
child: CircularPercentIndicator(
radius: 120.0,
lineWidth: 10.0,
animation: true,
center: ValueListenableBuilder(
valueListenable: _myPercentage,
builder:
(BuildContext context, double value, Widget? child) {
return Text(
'$value', // <- this text should be updated
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 20.0),
);
}),
footer: const Text(
'Remaining percentage',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 17.0),
),
circularStrokeCap: CircularStrokeCap.round,
progressColor: Colors.orange,
),
),
),
SafeArea(
child: _buildUsersFromDB(),
),
],
),
),
);
}
Widget _buildUsersFromDB() {
return FutureBuilder<List<User>>(
future: _userDAO.readData(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int i) {
return Card(
elevation: 2,
margin: const EdgeInsets.all(5),
child: _buildRow(snapshot.data![i]),
);
},
)
: const Center(
child: CircularProgressIndicator(),
);
});
}
Widget _buildRow(User user) {
_myPercentage.value -= user.percentage; // <- This line gives me problems
return ListTile(
title: Text(
user.name,
style: _biggerFont,
),
trailing: Text('${user.percentage} %'),
onTap: () => _showDoubleDialog(user).then((value) {
/* some code */
}),
);
}
}
但是当我 运行 应用程序时,出现以下错误:
════════ Exception caught by foundation library ════════════════════════════════
The following assertion was thrown while dispatching notifications for ValueNotifier<double>:
setState() or markNeedsBuild() called during build.
This ValueListenableBuilder<double> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: ValueListenableBuilder<double>
state: _ValueListenableBuilderState<double>#5709e
The widget which was currently being built when the offending call was made was: SliverList
delegate: SliverChildBuilderDelegate#e6e08(estimated child count: 3)
renderObject: RenderSliverList#aacf6 relayoutBoundary=up15 NEEDS-LAYOUT NEEDS-PAINT
When the exception was thrown, this was the stack
#0 Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:4217
#1 Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:4232
#2 State.setState
package:flutter/…/widgets/framework.dart:1108
#3 _ValueListenableBuilderState._valueChanged
package:flutter/…/widgets/value_listenable_builder.dart:182
#4 ChangeNotifier.notifyListeners
package:flutter/…/foundation/change_notifier.dart:243
...
The ValueNotifier<double> sending notification was: ValueNotifier<double>#5ee2d(89.2)
有没有人知道我如何实现这个或者在构建之后尝试设置小部件时的最佳实践是什么during/right?
编辑:我需要 ValueNotifier,因为每当更新单个用户的百分比时我都需要更新剩余百分比(通过点击用户并选择新百分比来完成)
我只想将调用移至 _userDAO.readData()
并添加 header 文本并基于此列出项目。这将消除对 _myPercentage
ValueNotifier
.
的需要
我在构建页面时尝试计算百分比并将其作为文本设置到文本小部件中。在我的应用程序中,我有一个带有 ListTile 的设置页面,它通过点击将用户带到一个新页面。在新页面 (percentage_settings_page.dart) 中,我从我的 SQLITE 数据库中读取数据,其中包含一些使用 FutureBuilder<List<User>>
和 ListView.builder()
.
在构建包含每个用户的名称和百分比的列表视图时,我需要计算剩余百分比,这是通过从 100 中减去用户百分比的总和得出的,并将其设置在循环指示器中。我正在尝试使用 ValueNotifier
来实现这一点。页面是这样的:
How it is: displaying 100
How it should be
percentage_settings_page.dart
:
class _PercentageSettingsPageState extends State<PercentageSettingsPage> {
/* other variables */
final ValueNotifier<double> _myPercentage = ValueNotifier<double>(100);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Divide percentage'),
leading: BackButton(
onPressed: () async => Navigator.pop(context),
),
),
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 20),
child: Align(
alignment: Alignment.topCenter,
child: CircularPercentIndicator(
radius: 120.0,
lineWidth: 10.0,
animation: true,
center: ValueListenableBuilder(
valueListenable: _myPercentage,
builder:
(BuildContext context, double value, Widget? child) {
return Text(
'$value', // <- this text should be updated
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 20.0),
);
}),
footer: const Text(
'Remaining percentage',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 17.0),
),
circularStrokeCap: CircularStrokeCap.round,
progressColor: Colors.orange,
),
),
),
SafeArea(
child: _buildUsersFromDB(),
),
],
),
),
);
}
Widget _buildUsersFromDB() {
return FutureBuilder<List<User>>(
future: _userDAO.readData(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int i) {
return Card(
elevation: 2,
margin: const EdgeInsets.all(5),
child: _buildRow(snapshot.data![i]),
);
},
)
: const Center(
child: CircularProgressIndicator(),
);
});
}
Widget _buildRow(User user) {
_myPercentage.value -= user.percentage; // <- This line gives me problems
return ListTile(
title: Text(
user.name,
style: _biggerFont,
),
trailing: Text('${user.percentage} %'),
onTap: () => _showDoubleDialog(user).then((value) {
/* some code */
}),
);
}
}
但是当我 运行 应用程序时,出现以下错误:
════════ Exception caught by foundation library ════════════════════════════════
The following assertion was thrown while dispatching notifications for ValueNotifier<double>:
setState() or markNeedsBuild() called during build.
This ValueListenableBuilder<double> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: ValueListenableBuilder<double>
state: _ValueListenableBuilderState<double>#5709e
The widget which was currently being built when the offending call was made was: SliverList
delegate: SliverChildBuilderDelegate#e6e08(estimated child count: 3)
renderObject: RenderSliverList#aacf6 relayoutBoundary=up15 NEEDS-LAYOUT NEEDS-PAINT
When the exception was thrown, this was the stack
#0 Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:4217
#1 Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:4232
#2 State.setState
package:flutter/…/widgets/framework.dart:1108
#3 _ValueListenableBuilderState._valueChanged
package:flutter/…/widgets/value_listenable_builder.dart:182
#4 ChangeNotifier.notifyListeners
package:flutter/…/foundation/change_notifier.dart:243
...
The ValueNotifier<double> sending notification was: ValueNotifier<double>#5ee2d(89.2)
有没有人知道我如何实现这个或者在构建之后尝试设置小部件时的最佳实践是什么during/right?
编辑:我需要 ValueNotifier,因为每当更新单个用户的百分比时我都需要更新剩余百分比(通过点击用户并选择新百分比来完成)
我只想将调用移至 _userDAO.readData()
并添加 header 文本并基于此列出项目。这将消除对 _myPercentage
ValueNotifier
.