Search code examples
flutterdartsetstateflutter-listviewstatefulwidget

Refresh listview based on button click


I have a list of categories and products. I want that when I click on a category:

  1. The selected category should change color to orange.
  2. The products listview should be refreshed with the selected category's products.

I tried to add setState and try to change both color and listview but that did not work. Any ideas what I need to rectify?

  Future fetchProducts() async {
    return await Provider.of<Products>(context, listen: false)
        .fetchAndSetProducts('title', false);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[100],
      appBar: AppBar(
        backgroundColor: Colors.grey[100],
        elevation: 0,
        brightness: Brightness.light,
        leading: Icon(null),
        actions: <Widget>[
          IconButton(
            onPressed: () {},
            icon: Icon(
              Icons.shopping_basket,
              color: Colors.grey[800],
            ),
          )
        ],
      ),
      body: SafeArea(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
                padding: EdgeInsets.symmetric(horizontal: 10.0),
                child: FutureBuilder(
                    future: _screenFuture,
                    // ignore: missing_return
                    builder: (context, snap) {
                      if (snap.error != null &&
                          !snap.error
                              .toString()
                              .contains('NoSuchMethodError')) {
                        return Center(child: Text('Something went wrong!'));
                      } else if (snap.hasData) {
                        var categoriesData = Provider.of<Categories>(context);
                        return Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            FadeAnimation(
                                1,
                                Text(
                                  'Food Delivery',
                                  style: TextStyle(
                                      color: Colors.grey[80],
                                      fontWeight: FontWeight.bold,
                                      fontSize: 30),
                                )),
                            SizedBox(
                              height: 20,
                            ),
                            Container(
                                height: 50,
                                child: ListView.builder(
                                    scrollDirection: Axis.horizontal,
                                    itemCount: categoriesData.items.length,
                                    itemBuilder: (ctx, i) => FadeAnimation(
                                        i.toDouble(),
                                        makeCategory(
                                            isActive: i.toDouble() == 0
                                                ? true
                                                : false,
                                            title: categoriesData.items
                                                .toList()[i]
                                                .title)))),
                            SizedBox(
                              height: 10,
                            ),
                          ],
                        );
                      } else if (snap.connectionState ==
                          ConnectionState.waiting) {
                        //return Container();
                        return Center(child: Spinner());
                      }
                    })),
            Padding(
                padding: EdgeInsets.symmetric(horizontal: 20.0),
                child: FutureBuilder(
                    future: _productScreenFuture,
                    // ignore: missing_return
                    builder: (context, snap) {
                      if (snap.error != null &&
                          !snap.error
                              .toString()
                              .contains('NoSuchMethodError')) {
                        return Center(child: Text('Something went wrong!'));
                      } else if (snap.hasData) {
                        productsData = Provider.of<Products>(context);
                        return Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisSize: MainAxisSize.min,
                          children: <Widget>[
                            FadeAnimation(
                                1,
                                Text(
                                  'Food Delivery',
                                  style: TextStyle(
                                      color: Colors.grey[80],
                                      fontWeight: FontWeight.bold,
                                      fontSize: 30),
                                )),
                            SizedBox(
                              height: 20,
                            ),
                            SizedBox(
                                height: 300,
                                child: ListView.builder(
                                    shrinkWrap: true,
                                    scrollDirection: Axis.horizontal,
                                    itemCount: productsData.items.length,
                                    itemBuilder: (ctx, i) => FadeAnimation(
                                        1.4,
                                        makeItem(
                                            image: 'assets/images/one.jpg',
                                            title: productsData.items[i].title,
                                            price:
                                                productsData.items[i].price)))),
                            SizedBox(
                              height: 10,
                            ),
                          ],
                        );
                      } else if (snap.connectionState ==
                          ConnectionState.waiting) {
                        //return Container();
                        return Center(child: Spinner());
                      }
                    })),
            SizedBox(
              height: 30,
            )
          ],
        ),
      ),
    );
  }

  Widget makeCategory({isActive, title}) {
    return AspectRatio(
        aspectRatio: isActive ? 3 : 2.5 / 1,
        child: GestureDetector(
          onTap: () {
            print(title + " clicked");
            setState(() {
              isActive = true;
              productsData = Provider.of<Products>(context, listen: false)
                  .findBycategoryName(title);
              print(productsData.first.title); // << data is available
            });
          },
          child: Container(
            margin: EdgeInsets.only(right: 10),
            decoration: BoxDecoration(
              color: isActive ? Colors.yellow[700] : Colors.white,
              borderRadius: BorderRadius.circular(50),
            ),
            child: Align(
              child: Text(
                title,
                style: TextStyle(
                    color: isActive ? Colors.white : Colors.grey[500],
                    fontSize: 18,
                    fontWeight: isActive ? FontWeight.bold : FontWeight.w100),
              ),
            ),
          ),
        ));
  }

  Widget makeItem({image, String title, double price}) {
    return AspectRatio(
      aspectRatio: 1 / 1.5,
      child: GestureDetector(
        child: Container(
          margin: EdgeInsets.only(right: 20),
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(20),
              image: DecorationImage(
                image: AssetImage(image),
                fit: BoxFit.cover,
              )),
          child: Container(
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                gradient: LinearGradient(begin: Alignment.bottomCenter, stops: [
                  .2,
                  .9
                ], colors: [
                  Colors.black.withOpacity(.9),
                  Colors.black.withOpacity(.3),
                ])),
            child: //Expanded(
                Padding(
              padding: EdgeInsets.all(20.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Align(
                    alignment: Alignment.topRight,
                    child: Icon(
                      Icons.favorite,
                      color: Colors.white,
                    ),
                  ),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Text(
                        "\Tsh. $price",
                        style: TextStyle(
                            color: Colors.white,
                            fontSize: 20,
                            fontWeight: FontWeight.bold),
                      ),
                      SizedBox(
                        height: 10,
                      ),
                      Text(
                        title,
                        style: TextStyle(color: Colors.white, fontSize: 20),
                      )
                    ],
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Solution

  • Actually When you call setState() your isActive is again changed to false because of this code:

    makeCategory(
      isActive: i.toDouble() == 0
      ? true
      : false,
    

    TRY THIS CODE:

     bool currentCategory = 0;
    
     Future fetchProducts() async {
    return await Provider.of<Products>(context, listen: false)
        .fetchAndSetProducts('title', false);
    
    
    }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.grey[100],
          appBar: AppBar(
            backgroundColor: Colors.grey[100],
            elevation: 0,
            brightness: Brightness.light,
            leading: Icon(null),
            actions: <Widget>[
              IconButton(
                onPressed: () {},
                icon: Icon(
                  Icons.shopping_basket,
                  color: Colors.grey[800],
                ),
              )
            ],
          ),
          body: SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Padding(
                    padding: EdgeInsets.symmetric(horizontal: 10.0),
                    child: FutureBuilder(
                        future: _screenFuture,
                        // ignore: missing_return
                        builder: (context, snap) {
                          if (snap.error != null &&
                              !snap.error
                                  .toString()
                                  .contains('NoSuchMethodError')) {
                            return Center(child: Text('Something went wrong!'));
                          } else if (snap.hasData) {
                            var categoriesData = Provider.of<Categories>(context);
                            return Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: <Widget>[
                                FadeAnimation(
                                    1,
                                    Text(
                                      'Food Delivery',
                                      style: TextStyle(
                                          color: Colors.grey[80],
                                          fontWeight: FontWeight.bold,
                                          fontSize: 30),
                                    )),
                                SizedBox(
                                  height: 20,
                                ),
                                Container(
                                    height: 50,
                                    child: ListView.builder(
                                        scrollDirection: Axis.horizontal,
                                        itemCount: categoriesData.items.length,
                                        itemBuilder: (ctx, i) => FadeAnimation(
                                            i.toDouble(),
                                            makeCategory(
                                                isActive: i == currentCategory 
                                                    ? true
                                                    : false,
                                                position: i,
                                                title: categoriesData.items
                                                    .toList()[i]
                                                    .title)))),
                                SizedBox(
                                  height: 10,
                                ),
                              ],
                            );
                          } else if (snap.connectionState ==
                              ConnectionState.waiting) {
                            //return Container();
                            return Center(child: Spinner());
                          }
                        })),
                Padding(
                    padding: EdgeInsets.symmetric(horizontal: 20.0),
                    child: FutureBuilder(
                        future: _productScreenFuture,
                        // ignore: missing_return
                        builder: (context, snap) {
                          if (snap.error != null &&
                              !snap.error
                                  .toString()
                                  .contains('NoSuchMethodError')) {
                            return Center(child: Text('Something went wrong!'));
                          } else if (snap.hasData) {
                            productsData = Provider.of<Products>(context);
                            return Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              mainAxisSize: MainAxisSize.min,
                              children: <Widget>[
                                FadeAnimation(
                                    1,
                                    Text(
                                      'Food Delivery',
                                      style: TextStyle(
                                          color: Colors.grey[80],
                                          fontWeight: FontWeight.bold,
                                          fontSize: 30),
                                    )),
                                SizedBox(
                                  height: 20,
                                ),
                                SizedBox(
                                    height: 300,
                                    child: ListView.builder(
                                        shrinkWrap: true,
                                        scrollDirection: Axis.horizontal,
                                        itemCount: productsData.items.length,
                                        itemBuilder: (ctx, i) => FadeAnimation(
                                            1.4,
                                            makeItem(
                                                image: 'assets/images/one.jpg',
                                                title: productsData.items[i].title,
                                                price:
                                                    productsData.items[i].price)))),
                                SizedBox(
                                  height: 10,
                                ),
                              ],
                            );
                          } else if (snap.connectionState ==
                              ConnectionState.waiting) {
                            //return Container();
                            return Center(child: Spinner());
                          }
                        })),
                SizedBox(
                  height: 30,
                )
              ],
            ),
          ),
        );
      }
    
      Widget makeCategory({isActive, title, position}) {
        return AspectRatio(
            aspectRatio: isActive ? 3 : 2.5 / 1,
            child: GestureDetector(
              onTap: () {
                print(title + " clicked");
                setState(() {
                  currentCategory = position;
                  productsData = Provider.of<Products>(context, listen: false)
                      .findBycategoryName(title);
                  print(productsData.first.title); // << data is available
                });
              },
              child: Container(
                margin: EdgeInsets.only(right: 10),
                decoration: BoxDecoration(
                  color: isActive ? Colors.yellow[700] : Colors.white,
                  borderRadius: BorderRadius.circular(50),
                ),
                child: Align(
                  child: Text(
                    title,
                    style: TextStyle(
                        color: isActive ? Colors.white : Colors.grey[500],
                        fontSize: 18,
                        fontWeight: isActive ? FontWeight.bold : FontWeight.w100),
                  ),
                ),
              ),
            ));
      }
    
      Widget makeItem({image, String title, double price}) {
        return AspectRatio(
          aspectRatio: 1 / 1.5,
          child: GestureDetector(
            child: Container(
              margin: EdgeInsets.only(right: 20),
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(20),
                  image: DecorationImage(
                    image: AssetImage(image),
                    fit: BoxFit.cover,
                  )),
              child: Container(
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(20),
                    gradient: LinearGradient(begin: Alignment.bottomCenter, stops: [
                      .2,
                      .9
                    ], colors: [
                      Colors.black.withOpacity(.9),
                      Colors.black.withOpacity(.3),
                    ])),
                child: //Expanded(
                    Padding(
                  padding: EdgeInsets.all(20.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Align(
                        alignment: Alignment.topRight,
                        child: Icon(
                          Icons.favorite,
                          color: Colors.white,
                        ),
                      ),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                          Text(
                            "\Tsh. $price",
                            style: TextStyle(
                                color: Colors.white,
                                fontSize: 20,
                                fontWeight: FontWeight.bold),
                          ),
                          SizedBox(
                            height: 10,
                          ),
                          Text(
                            title,
                            style: TextStyle(color: Colors.white, fontSize: 20),
                          )
                        ],
                      )
                    ],
                  ),
                ),
              ),
            ),
          ),
        );
      }
    }