flutterdartfutureflutter-futurebuilderstatefulwidget

Widget reloads again on child item/widget click in flutter


I have a stateful widget, i am facing a strange issue whenever i click on any sub item such as CustomDropDownButtonFormField and its open drop down menu even before selecting any option in drop down menu its invoke Widget build(BuildContext context) and reload the screen. This is a strange behaviour. I also try by commenting setState everywhere in this widget but this issue still exists. I spent a lot of time on it. But I am not able to resolve this issue. Please take a look at my code and let me know what is wrong with it.



class ProductThreeShopScreen extends StatefulWidget {
  const ProductThreeShopScreen({
    Key? key,
    required this.childCategoryCatalogModel,
  }) : super(key: key);
  final CategoryCatalogModel childCategoryCatalogModel;

  State<ProductThreeShopScreen> createState() =>
      __ProductThreeShopScreenState();
}

class __ProductThreeShopScreenState extends State<ProductThreeShopScreen> {
  double widgetWitdh = 320;
  double widgetHeight = 620;
  double widgetHeightHalf = 470;
  double gridMainAxisSpacing = 10;

  Timer? _timer;
  Icon icona = const Icon(Icons.search);
  TextEditingController nameDescSearchController = TextEditingController();
  bool viewOutOfAssortment = false;
  bool readImageData = true;
  bool readAlsoDeleted = false;
  int selectedCategory = 0;
  List<DropdownMenuItem<String>> availableCategory = [];

  String numberResult = '10';
  List<DropdownMenuItem<String>> availableNumberResult = [
    DropdownMenuItem(child: Text("10"), value: "10"),
    DropdownMenuItem(child: Text("25"), value: "25"),
  ];

  String orderBy = 'NameProduct';
  List<DropdownMenuItem<String>> availableOrderBy = [
    DropdownMenuItem(child: Text("Name"), value: "NameProduct"),
    DropdownMenuItem(child: Text("Des"), value: "DescriptionProduct"),
  ];
  Icon iconaNameDescSearch = const Icon(Icons.search);

  void onChangeCategory(value) {
    setState(() {
      selectedCategory = value!;
    });
  }

  void onChangeNumberResult(value) {
    setState(() {
      numberResult = value!;
    });
  }

  void onChangeOrderBy(value) {
    setState(() {
      orderBy = value!;
    });
  }

  @override
  void initState() {
    nameDescSearchController.text = "";
    viewOutOfAssortment = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    AuthenticationNotifier authenticationNotifier =
        Provider.of<AuthenticationNotifier>(context);

    // ProjectNotifier projectNotifier = Provider.of<ProjectNotifier>(context);
    // StoreNotifier storeNotifier = Provider.of<StoreNotifier>(context);
    UserAppInstitutionModel cUserAppInstitutionModel =
        authenticationNotifier.getSelectedUserAppInstitution();
    // bool canAddProduct = authenticationNotifier.canUserAddItem();

    return SafeArea(
        child: Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      // drawer: const CustomDrawerWidget(),
      appBar: AppBar(
        centerTitle: true,
        title: Text(widget.childCategoryCatalogModel.nameCategory,
            style: Theme.of(context).textTheme.headlineLarge),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            Row(
              children: [
                Expanded(
                    flex: 1,
                    child: CustomDropDownButtonFormField(
                      enabled: true,
                      actualValue: numberResult,
                      labelText: 'Mostra numero risultati',
                      listOfValue: availableNumberResult,
                      onItemChanged: (value) {
                        onChangeNumberResult(value);
                      },
                    )),
                Expanded(
                    flex: 2,
                    child: CustomDropDownButtonFormField(
                      enabled: true,
                      actualValue: orderBy,
                      labelText: 'Ordinamento',
                      listOfValue: availableOrderBy,
                      onItemChanged: (value) {
                        onChangeOrderBy(value);
                      },
                    )),
                Expanded(
                  flex: 1,
                  child: CheckboxListTile(
                    side: const BorderSide(color: Colors.blueGrey),
                    checkColor: Colors.blueAccent,
                    checkboxShape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(15)),
                    activeColor: Colors.blueAccent,

                    controlAffinity: ListTileControlAffinity.leading,
                    value: viewOutOfAssortment,
                    onChanged: (bool? value) {
                      setState(() {
                        viewOutOfAssortment = value!;
                      });
                    },
                    title: Text(
                      'Visualizza fuori assortimento',
                      style: Theme.of(context)
                          .textTheme
                          .labelMedium!
                          .copyWith(color: Colors.blueGrey),
                    ),
                    // subtitle: const Text(""),
                  ),
                ),
                Expanded(
                  flex: 1,
                  child: CheckboxListTile(
                    side: const BorderSide(color: Colors.blueGrey),
                    checkColor: Colors.blueAccent,
                    checkboxShape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(15)),
                    activeColor: Colors.blueAccent,

                    controlAffinity: ListTileControlAffinity.leading,
                    value: readImageData,
                    onChanged: (bool? value) {
                      setState(() {
                        readImageData = value!;
                      });
                    },
                    title: Text(
                      'Visualizza immagine',
                      style: Theme.of(context)
                          .textTheme
                          .labelMedium!
                          .copyWith(color: Colors.blueGrey),
                    ),
                    // subtitle: const Text(""),
                  ),
                ),
                Expanded(
                  flex: 2,
                  child: TextFormField(
                    style: Theme.of(context)
                        .textTheme
                        .labelLarge!
                        .copyWith(color: Colors.blueGrey),
                    onChanged: (String value) {
                      if (_timer?.isActive ?? false) {
                        _timer!.cancel();
                      }
                      _timer = Timer(const Duration(milliseconds: 1000), () {
                        setState(() {
                          iconaNameDescSearch = const Icon(Icons.cancel);
                          if (value.isEmpty) {
                            iconaNameDescSearch = const Icon(Icons.search);
                          }
                        });
                      });
                    },
                    controller: nameDescSearchController,
                    decoration: InputDecoration(
                      labelText: "Ricerca per nome, descrizione o barcode",
                      labelStyle: Theme.of(context)
                          .textTheme
                          .labelMedium!
                          .copyWith(color: Colors.blueGrey),
                      hintText: "Ricerca per nome, descrizione o barcode",
                      hintStyle: Theme.of(context)
                          .textTheme
                          .labelLarge!
                          .copyWith(
                              color:
                                  Theme.of(context).hintColor.withOpacity(0.3)),
                      suffixIcon: IconButton(
                        icon: iconaNameDescSearch,
                        onPressed: () {
                          setState(() {
                            if (iconaNameDescSearch.icon == Icons.search) {
                              iconaNameDescSearch = const Icon(Icons.cancel);
                            } else {
                              iconaNameDescSearch = const Icon(Icons.search);
                              nameDescSearchController.text = "";
                            }
                          });
                        },
                      ),
                      floatingLabelBehavior: FloatingLabelBehavior.always,
                      border: const OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0)),
                        borderSide: BorderSide(color: Colors.grey, width: 1.0),
                      ),
                      enabledBorder: const OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0)),
                        borderSide: BorderSide(color: Colors.grey, width: 1.0),
                      ),
                      focusedBorder: const OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0)),
                        borderSide: BorderSide(color: Colors.blue, width: 1.0),
                      ),
                      errorBorder: const OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0)),
                        borderSide: BorderSide(color: Colors.red, width: 1.0),
                      ),
                      focusedErrorBorder: const OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(10.0)),
                        borderSide: BorderSide(
                            color: Colors.deepOrangeAccent, width: 1.0),
                      ),
                    ),
                  ),
                ),
              ],
            ),
            SizedBox(
              height: MediaQuery.of(context).size.height,
              width: MediaQuery.of(context).size.width,
              child: Consumer<ProductCatalogNotifier>(
                builder: (context, productCatalogNotifier, _) {
                  return SizedBox(
                    height: MediaQuery.of(context).size.height * 0.8,
                    width: MediaQuery.of(context).size.width,
                    child: FutureBuilder(
                      future: productCatalogNotifier.getProducts(
                          context: context,
                          token: authenticationNotifier.token,
                          idUserAppInstitution:
                              cUserAppInstitutionModel.idUserAppInstitution,
                          idCategory:
                              widget.childCategoryCatalogModel.idCategory,
                          readAlsoDeleted: false,
                          numberResult: numberResult,
                          nameDescSearch: nameDescSearchController.text,
                          orderBy: orderBy,
                          readImageData: readImageData,
                          shoWVariant: true,
                          viewOutOfAssortment: viewOutOfAssortment),
                      builder: (context, snapshot) {
                        if (snapshot.connectionState ==
                            ConnectionState.waiting) {
                          return const Center(
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Center(
                                    child: SizedBox(
                                        width: 100,
                                        height: 100,
                                        child: CircularProgressIndicator(
                                          strokeWidth: 5,
                                          color: Colors.redAccent,
                                        ))),
                              ],
                            ),
                          );
                        } else if (!snapshot.hasData) {
                          return const Center(
                            child: Text(
                              'No data...',
                              style: TextStyle(
                                color: Colors.redAccent,
                              ),
                            ),
                          );
                        } else {
                          var tSnapshot =
                              snapshot.data as List<ProductCatalogModel>;
                          var t = tSnapshot
                              .any((element) => element.imageData.isNotEmpty);
                          bool areAllWithNoImage = !t;
                          double cHeight = 0;
                          if (areAllWithNoImage) {
                            cHeight = widgetHeightHalf;
                          } else {
                            cHeight = widgetHeight;
                          }
                          return GridView.builder(
                              gridDelegate:
                                  SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight(
                                crossAxisCount:
                                    (MediaQuery.of(context).size.width) ~/
                                        widgetWitdh,
                                crossAxisSpacing: 10,
                                mainAxisSpacing: gridMainAxisSpacing,
                                height: cHeight,
                              ),
                              physics: const ScrollPhysics(),
                              shrinkWrap: true,
                              itemCount: tSnapshot.length,
                              // scrollDirection: Axis.horizontal,
                              itemBuilder: (context, index) {
                                ProductCatalogModel productCatalog =
                                    tSnapshot[index];
                                return ProductCard(
                                    productCatalog: productCatalog,
                                    areAllWithNoImage: areAllWithNoImage);
                              });
                        }
                      },
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    ));
  }
}

Solution

  • I faced similar issue. I was setting model data by using tSnapshot when calling the constructor. I fixed it by not passing the model in the constructor and I use Notifier to set the data before I navigating to the widget and I use Notifier to get the data where I needed.

    Try these things:

    When you are navigating to this screen then use notifier for setting the data

     yourCategoryCatalogNotifier.setCurrentCategoryCatalog(category);
     Navigator.of(context).pushNamed(AppRouter.yourRoute);
    //rest of your code                                    
                                        
    

    In your widget update the constructor:

       const ProductThreeShopScreen({
        Key? key,
      }) : super(key: key);
                                      
                                      
    

    And in this widget where you would like to access the data, use notifier to access it

     YourCategoryCatalogNotifier yourcategoryCatalogNotifier =
            Provider.of<yourCategoryCatalogNotifier>(context);
    
     title: Text(
            youCategoryCatalogNotifier.getCurrentCategoryCatalog().nameCategory,
            style: Theme.of(context).textTheme.headlineLarge)