i want to make each item of my list item widget clickable, but the gesture detector keeps bringing errors of setState not been set

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

This Overlay 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: Overlay-[LabeledGlobalKey#82394] state: OverlayState#6588e(entries: [OverlayEntry#76289(opaque: true; maintainState: false), OverlayEntry#e77e5(opaque: false; maintainState: true), OverlayEntry#6b5f4(opaque: true; maintainState: false), OverlayEntry#7123e(opaque: false; maintainState: true), OverlayEntry#89745(opaque: false; maintainState: false), OverlayEntry#16a91(opaque: false; maintainState: true), OverlayEntry#f64eb(opaque: false; maintainState: false), OverlayEntry#9ff75(opaque: false; maintainState: true)]) The widget which was currently being built when the offending call was made was: ProductList dirty.

This was the error.

While down here is the widget

class ProductList extends StatelessWidget {
  final String imageurl;
  final String item;
  final String subtitle;
  final Function press;

  const ProductList({Key? key, required this.imageurl, required this.item, required this.subtitle, required this.press}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: GestureDetector(
        onTap: press(),
        child: ListTile(
          leading: CircleAvatar(
            radius: 20,
            backgroundImage: AssetImage(imageurl),
          ),
          title: Text(item),
          subtitle: Text(subtitle),
        ),
      ),
    );
  }
}

and here is the widget where the press function is used

import 'package:flutter/material.dart';
import 'package:moni_test/pages/product/pages/gaming.dart';
import 'package:moni_test/pages/product/productlistitem.dart';


class ProductMenu extends StatefulWidget {
  const ProductMenu({Key? key}) : super(key: key);

  @override
  _ProductMenuState createState() => _ProductMenuState();
}

class _ProductMenuState extends State<ProductMenu> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

      body: Container(
        padding: EdgeInsets.only(top: 20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            ProductList(
              press: () {
                 Navigator.push(context,
                     MaterialPageRoute(builder: (context) {
                       return Gaming();
                     }));
              },
              imageurl: "assets/images/kindpng_174783.png",
              item: "Gaming",
              subtitle: "Consoles, Controllers",),
            SizedBox(
              height: 20,
            ),
            ProductList(
                press: () {},
                imageurl: "assets/images/kindpng_4886049.png",
                item: "Sneakers",
                subtitle: "Puma, Nike, Addidas")
          ],
        ),
      ),
    );
  }
}

Upvotes: 0

Views: 196

Answers (2)

anggadaz
anggadaz

Reputation: 390

wrap setstate with addPostFrameCallback

WidgetsBinding.instance.addPostFrameCallback((callback) {
      
    });

Upvotes: 0

TDuff
TDuff

Reputation: 78

onTap: press(), shouldn't have the trailing (), as this will run the function during build, which is likely what is causing your error. You want to store the function signature (tear-off) for dart to run later, rather than run it immediately.

If that's giving you errors (onTap will only accept a VoidCallback? so sometimes your function might not match this signature) you can wrap it in a closure:

ontap: (){press();} which will have your desired effect.

Other comments about wrapping addPostFrameCallback around your problematic code can also be useful in other circumstances (say, you want to want to modify the content of the widget tree later on during build()) but in this case I'm going to assume it's the function being called when it should be a tear-off instead.

Try this video for some background on tearoffs and closures. You might find something useful here! https://www.youtube.com/watch?v=OmCaloD7sis&t=147s

Upvotes: 1

Related Questions