在构建 ItemCard(dirty) 时抛出了以下断言:setState() 或 markNeedsBuild() 在构建期间调用

时间:2021-06-26 18:42:42

标签: flutter flutter-layout flutter-web flutter-animation flutter-test

我是 Flutter 新手,我正在尝试构建一个在线购物应用作为我的毕业项目。

每次我运行应用程序时,它都会直接进入“物品卡片”方法并通过它进入“详细信息屏幕”,即使它应该只在按下导航器小部件时才会进入。

它还将物品卡标记为肮脏的孩子(我不太明白这是什么意思以及如何将其恢复为正常孩子)。

   Error message: The following assertion was thrown building ItemCard(dirty):
setState() or markNeedsBuild() called during build.

我希望我能很好地解释错误..这是代码, 首先是 Body 类,然后是 Item Card 类,然后是 Details Screen 类:

    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)
      ],
    );
  }
}

2 个答案:

答案 0 :(得分:0)

正在立即调用 onPress 中的 GestureDetector 函数。

有两种方法可以解决问题。

  1. 删除对函数的调用,方法是删除 ()
  2. 将 press 函数包装在一个匿名函数中,以便稍后在用户实际执行操作时调用我,这通常在您需要评估变量时完成,例如在 onChanged 处理程序中TextFieldTextFormField

检查下面的代码片段。

方法 1 的示例。

@override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: press,
      child: ...
   )
}

方法 2 示例:

@override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => press(),
      child: ...
   )
}

答案 1 :(得分:0)

将其推迟到下一个刻度会起作用 -

上一个

@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: ...
   )
}