构建 ItemCard(dirty) 时引发了以下断言:在构建期间调用了 setState() 或 markNeedsBuild()
The following assertion was thrown building ItemCard(dirty): setState() or markNeedsBuild() called during build
我是 Flutter 新手,我正在尝试构建一个在线购物应用程序作为我的毕业设计。
每次我 运行 该应用程序都会直接进入“项目卡”方法并通过它进入“详细信息屏幕”,即使它应该只在按下导航器小部件时才会到达那里。
它还将物品卡标记为脏 child(我不太明白这意味着什么以及如何将其恢复为正常 child)。
Error message: The following assertion was thrown building ItemCard(dirty):
setState() or markNeedsBuild() called during build.
我希望我对错误的解释足够好。这是代码,
首先是主体 class,然后是物品卡 class,然后是详情屏幕 class:
class Body extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
child: Text(
"Mobiles",
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(fontWeight: FontWeight.bold),
),
),
Categories(),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
child: GridView.builder(
itemCount: productz.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: kDefaultPaddin,
crossAxisSpacing: kDefaultPaddin,
childAspectRatio: 0.75,
),
itemBuilder: (context, index) => ItemCard(
productz: productz[index],
press: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsScreen(
productz: productz[index],
),
)),
)),
),
),
],
);
}
}
class ItemCard extends StatelessWidget {
final Productz productz;
final Function press;
const ItemCard({
Key? key,
required this.productz,
required this.press,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(kDefaultPaddin),
decoration: BoxDecoration(
color: Colors.white12,
borderRadius: BorderRadius.circular(16),
),
child: Hero(
tag: "${productz.id}",
child: Image.asset(productz.item_image),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: kDefaultPaddin / 4),
child: Text(
// products is out demo list
productz.item_name,
style: TextStyle(color: kTextLightColor),
),
),
Text(
"$${productz.item_price}",
style: TextStyle(fontWeight: FontWeight.bold),
)
],
),
);
}
}
class DetailsScreen extends StatelessWidget {
final Productz productz;
const DetailsScreen({Key? key, required this.productz}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
// each product have a color
backgroundColor: Colors.white12,
appBar: buildAppBar(context),
body: Body(productz: productz),
);
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white12,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back,
size: 30,
color: Colors.white,
),
onPressed: () => Navigator.pop(context),
),
actions: <Widget>[
IconButton(
icon: Icon(FontAwesomeIcons.search),
onPressed: () {},
),
IconButton(
icon: Icon(FontAwesomeIcons.shoppingCart),
onPressed: () {},
),
SizedBox(width: kDefaultPaddin / 2)
],
);
}
}
正在立即调用 GestureDetector
中的 onPress
函数。
您可以通过两种方式解决问题。
- 通过删除
()
来删除对函数的调用
- 将 press 函数包裹在一个匿名函数中,以便稍后当用户实际执行操作时调用 I,这通常在需要评估变量时执行,例如
onChanged
TextField
或 TextFormField
的处理程序
检查下面的代码片段。
方法 1 的示例。
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press,
child: ...
)
}
方法 2 的示例:
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => press(),
child: ...
)
}
将它推迟到下一个价格变动将起作用 -
上一个
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press();
child: ...
)
}
改为:
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: Future.delayed(Duration.zero, () async {
press();
}),
child: ...
)
}
我是 Flutter 新手,我正在尝试构建一个在线购物应用程序作为我的毕业设计。
每次我 运行 该应用程序都会直接进入“项目卡”方法并通过它进入“详细信息屏幕”,即使它应该只在按下导航器小部件时才会到达那里。
它还将物品卡标记为脏 child(我不太明白这意味着什么以及如何将其恢复为正常 child)。
Error message: The following assertion was thrown building ItemCard(dirty):
setState() or markNeedsBuild() called during build.
我希望我对错误的解释足够好。这是代码, 首先是主体 class,然后是物品卡 class,然后是详情屏幕 class:
class Body extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
child: Text(
"Mobiles",
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(fontWeight: FontWeight.bold),
),
),
Categories(),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPaddin),
child: GridView.builder(
itemCount: productz.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: kDefaultPaddin,
crossAxisSpacing: kDefaultPaddin,
childAspectRatio: 0.75,
),
itemBuilder: (context, index) => ItemCard(
productz: productz[index],
press: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsScreen(
productz: productz[index],
),
)),
)),
),
),
],
);
}
}
class ItemCard extends StatelessWidget {
final Productz productz;
final Function press;
const ItemCard({
Key? key,
required this.productz,
required this.press,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(kDefaultPaddin),
decoration: BoxDecoration(
color: Colors.white12,
borderRadius: BorderRadius.circular(16),
),
child: Hero(
tag: "${productz.id}",
child: Image.asset(productz.item_image),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: kDefaultPaddin / 4),
child: Text(
// products is out demo list
productz.item_name,
style: TextStyle(color: kTextLightColor),
),
),
Text(
"$${productz.item_price}",
style: TextStyle(fontWeight: FontWeight.bold),
)
],
),
);
}
}
class DetailsScreen extends StatelessWidget {
final Productz productz;
const DetailsScreen({Key? key, required this.productz}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
// each product have a color
backgroundColor: Colors.white12,
appBar: buildAppBar(context),
body: Body(productz: productz),
);
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white12,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back,
size: 30,
color: Colors.white,
),
onPressed: () => Navigator.pop(context),
),
actions: <Widget>[
IconButton(
icon: Icon(FontAwesomeIcons.search),
onPressed: () {},
),
IconButton(
icon: Icon(FontAwesomeIcons.shoppingCart),
onPressed: () {},
),
SizedBox(width: kDefaultPaddin / 2)
],
);
}
}
正在立即调用 GestureDetector
中的 onPress
函数。
您可以通过两种方式解决问题。
- 通过删除
()
来删除对函数的调用
- 将 press 函数包裹在一个匿名函数中,以便稍后当用户实际执行操作时调用 I,这通常在需要评估变量时执行,例如
onChanged
TextField
或TextFormField
的处理程序
检查下面的代码片段。
方法 1 的示例。
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press,
child: ...
)
}
方法 2 的示例:
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => press(),
child: ...
)
}
将它推迟到下一个价格变动将起作用 -
上一个
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press();
child: ...
)
}
改为:
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: Future.delayed(Duration.zero, () async {
press();
}),
child: ...
)
}