0

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),
                      )
                    ],
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
6
  • instead of isActive = true; try isActive = !isActive ; Commented Sep 7, 2021 at 17:19
  • Create seperate stateful widget for your makeItem and makeCategoryItem Commented Sep 7, 2021 at 18:19
  • People need the whole code to understand the whole context. I believe I have provided just enough code so that someone can run it locally. I have posted many questions in the past with incomplete code and people did not like it. Kindly be nice. Commented Sep 8, 2021 at 2:54
  • @TechnicalWorld, it's already in a stateful widget. However I tried creating a separate stateful widget as per your suggestion but it didn't work. Commented Sep 8, 2021 at 8:38
  • @Benyamin, that didn't work either. Commented Sep 8, 2021 at 8:39

2 Answers 2

1

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),
                      )
                    ],
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

the isActive is not a variable and when you change it in setState nothing happens. try using a int? index variable for saving your selected category index

1 Comment

Can you provide an example please?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.