How to use Gesture control and change color on chip selection in Flutter

166

Solution 1

Hope this helps

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  PageController pageController = PageController();
  int _selectedIndex = 0;

  void onTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
    pageController.jumpToPage(index);
  }
  
  @override
  void dispose() {
    pageController.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: PageView(
          controller: pageController,
          children: [
            const HomePage(),
            Container(
              color: Colors.blue,
            ),
            Container(
              color: Colors.white,
            ),
            Container(
              color: Colors.yellow,
            ),
            Container(
              color: Colors.blue,
            ),
            Container(
              color: Colors.white,
            ),
            Container(
              color: Colors.yellow,
            )
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
            BottomNavigationBarItem(
                icon: Icon(Icons.cleaning_services), label: 'Services'),
            BottomNavigationBarItem(
                icon: Icon(Icons.local_convenience_store), label: 'Store'),
            BottomNavigationBarItem(
                icon: Icon(Icons.account_balance_wallet), label: 'Wallet'),
            BottomNavigationBarItem(
                icon: Icon(Icons.bookmarks), label: 'Bookmarked'),
            BottomNavigationBarItem(
                icon: Icon(Icons.assessment), label: 'Current Orders'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
          ],
          currentIndex: _selectedIndex,
          selectedItemColor: Colors.red,
          unselectedItemColor: Colors.grey,
          onTap: onTapped,
        ));
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedCategoryIndex = 0;
  String _selectedUserType = "Maid";
  List array = [
    "Maid",
    "Driver",
    "Engineer",
    "Gardener",
    "Pilot",
    "carpainter",
    "guard",
    "plumber"
  ];

  List data = [
    {
      "name": "Sachin Rajput",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["Maid", "Engineer"],
      "rating": 5,
      "bg": Colors.red
    },
    {
      "name": "Sachin Tendulkar",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["Gardener", "Pilot", "Engineer"],
      "rating": 5,
      "bg": Colors.amberAccent
    },
    {
      "name": "Sachin Test",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["carpainter", "guard", "plumber"],
      "rating": 5,
      "bg": Colors.blue
    }
  ];
  List product_data = [
    {
      "name": "P1",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["Dusting"],
      "rating": 5,
      "bg": Colors.red
    },
    {
      "name": "P2",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["Mopping"],
      "rating": 5,
      "bg": Colors.amberAccent
    },
    {
      "name": "P3",
      "profilePic":
      "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
      "category": ["cleaning"],
      "rating": 5,
      "bg": Colors.blue
    }
  ];
  List filteredData = [];

  void tappedCategory(int index) {
    _selectedCategoryIndex = index;
    _selectedUserType = array[index];
    _filterData();
  }

  @override
  void initState() {
    super.initState();
    _filterData();
  }
  
  @override
  void dispose() {
    super.dispose();
  }

  _filterData() {
    filteredData = data
        .where((element) => element["category"].contains(_selectedUserType))
        .toList();
    setState(() {});
  }

  Widget customContainer({required IconData iconData}) {
    return Container(
      width: 45,
      height: 45,
      padding: const EdgeInsets.only(left: 0, right: 0),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(15),
        color: Colors.red,
      ),
      child: Icon(
        iconData,
        color: Colors.white,
      ),
    );
  }

  Widget customProductsList({required String title, required List dataList}) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(title),
              const Align(
                alignment: Alignment.centerRight,
                child: Text(
                  'View All',
                ),
              ),
            ],
          ),
        ),
        SizedBox(
          height: MediaQuery.of(context).size.height / 6,
          child: dataList.isNotEmpty
              ? ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: dataList.length,
            itemBuilder: (context, index) {
              var item = dataList[index];
              return Padding(
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: Container(
                  color: item['bg'],
                  child: Center(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 60),
                      child: Text(item["name"].toString()),
                    ),
                  ),
                ),
              );
            },
            // This next line does the trick.
          )
              : const Center(
            child: Text('No data found.'),
          ),
        ),
      ],
    );
  }
  
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 5),
              child: Container(
                // color: Colors.purple,
                // margin: const EdgeInsets.only(top: 45, bottom: 15),
                  padding: const EdgeInsets.only(left: 10, right: 10),
                  child: Row(children: [
                    Expanded(
                      child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              "Bengaluru",
                              style: TextStyle(
                                color: Colors.red,
                              ),
                            ),
                            const Text("R.T Nagar")
                          ]),
                    ),
                    customContainer(
                      iconData: Icons.search,
                    ),
                    const SizedBox(
                      width: 10,
                    ),
                    customContainer(
                      iconData: Icons.notifications,
                    ),
                  ])),
            ),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    const Padding(
                      padding: EdgeInsets.symmetric(
                          vertical: 10, horizontal: 10),
                      child: Align(
                        alignment: Alignment.centerLeft,
                        child: Text(
                          'Popular Services',
                        ),
                      ),
                    ),
                    SizedBox(
                      height: MediaQuery.of(context).size.height / 12,
                      child: ListView(
                        shrinkWrap: true,
                        scrollDirection: Axis.horizontal,
                        children: List<Widget>.generate(
                            array
                                .length, // place the length of the array here
                                (int index) {
                              return Container(
                                margin: const EdgeInsets.all(2.0),
                                child: GestureDetector(
                                  onTap: () {
                                    tappedCategory(index);
                                  },
                                  child: Chip(
                                    label: Text(array[index]),
                                    backgroundColor:
                                    _selectedCategoryIndex == index
                                        ? Colors.green
                                        : Colors.grey,
                                  ),
                                ),
                              );
                            }).toList(),
                      ),
                    ),
                    SizedBox(
                      height: MediaQuery.of(context).size.height / 6,
                      child: filteredData.isNotEmpty
                          ? ListView.builder(
                        scrollDirection: Axis.horizontal,
                        // physics: NeverScrollableScrollPhysics(),
                        itemCount: filteredData.length,
                        itemBuilder: (context, index) {
                          var item = filteredData[index];
                          return Padding(
                            padding: const EdgeInsets.symmetric(
                                horizontal: 10),
                            child: GestureDetector(
                              onTap: () {
                                Navigator.of(context).push(
                                    MaterialPageRoute(
                                        builder: (context) =>
                                            DetailPage(
                                                user: item)));
                              },
                              child: Container(
                                color: item['bg'],
                                child: Center(
                                  child: Padding(
                                    padding: const EdgeInsets
                                        .symmetric(
                                        horizontal: 20),
                                    child: Text(
                                        item["name"].toString()),
                                  ),
                                ),
                              ),
                            ),
                          );
                        },
                        // This next line does the trick.
                      )
                          : const Center(
                        child: Text(
                            "No records available for the selected category"),
                      ),
                    ),
                    customProductsList(
                        title: 'Popular Products',
                        dataList: product_data),
                    customProductsList(
                        title: 'Our Products', dataList: product_data),
                    customProductsList(
                        title: 'New Products', dataList: product_data)
                  ],
                ),
              ),
            )
          ]),
    );
  }
}

class DetailPage extends StatelessWidget {
  const DetailPage({Key? key, this.user}) : super(key: key);
  final dynamic user;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(user["name"]),
        ),
        body: Container(
          padding: EdgeInsets.all(8),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            // mainAxisAlignment: MainAxisAlignment.center,
            children: [
              CircleAvatar(child: Image.network(user["profilePic"]), minRadius: 60,),
              SizedBox(height: 10,),
              Text("${user["name"]}"),
            ],
          ),
        )
    );
  }
}

Solution 2

   Chip(
        label: "label",
        backgroundColor: _selectedCategoryIndex == index ? Colors.blue : Colors.green,
   ),

do not forgot to change tappedCategory function replace your function with this,

 void tappedCategory(int index) {
    _selectedCategoryIndex = index;
    _selectedUserType = array[index];
    _filterData();
    setState(() {});
  }

Solution 3

You can use: <true/false expressions> ? <if true> : <if false>

highlight the chip that is selected

Add an backgroundColor to Chip. index == _selectedCategoryIndex will check that chip is selected or not by index then set the color you want. In this case, that ex mean If the chip is selected chip, colored it!

- child: Chip(label: Text(array[index])),
+ child: Chip(
+   label: Text(array[index]),
+   backgroundColor: index == _selectedCategoryIndex ? APP_COLOR.mainColor : null),
+ )

so a text message stating Not Available if there is nothing available, rather then leaving blank and

Check filteredData have data then render what you want. In this case, ex mean If the filtered list is EMPTY, then render the Text insteads.

Detailer:

- Container(
-   height: MediaQuery.of(context).size.height / 6,
-   child: ListView.builder(...),
- ),
+ Container(
+   height: MediaQuery.of(context).size.height / 6,
+   child: filteredData.isNotEmpty
+     ? ListView.builder(...)
+     : Text('YOUR FILTERED LIST IS EMPTY'),
+ ),
Share:
166
Sachin Rajput
Author by

Sachin Rajput

Updated on January 05, 2023

Comments

  • Sachin Rajput
    Sachin Rajput 2 minutes

    context :

    I want to click on a particular services person/product and open a page where details can be shown more like a details page

    Problem

    I think that Gesture control should work but I'm not able to put it the right way in my code

    How to change chip color on selection the data is getting filtered but i want to add 2 more things

    1. highlight the chip that is selected
    2. so a text message stating Not Available if there is nothing available, rather then leaving blank and

    My Code

    class _HomeScreenState extends State<HomeScreen> {
      int _selectedIndex = 0;
      int _selectedCategoryIndex = -1;
      String _selectedUserType = "Maid";
      PageController pageController = PageController();
      List array = ["Maid", "Driver", "Engineer", "Gardener", "Pilot","carpainter", "guard", "plumber"];
    
      List data = [
        {
          "name": "Sachin Rajput",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["Maid", "Engineer"],
          "rating": 5,
          "bg": Colors.red
        },
        {
          "name": "Sachin Tendulkar",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["Gardener", "Pilot", "Engineer"],
          "rating": 5,
          "bg": Colors.amberAccent
        },
        {
          "name": "Sachin Test",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["carpainter", "guard", "plumber"],
          "rating": 5,
          "bg": Colors.blue
        }
      ];
      List product_data = [
        {
          "name": "P1",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["Dusting"],
          "rating": 5,
          "bg": Colors.red
        },
        {
          "name": "P2",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["Mopping"],
          "rating": 5,
          "bg": Colors.amberAccent
        },
        {
          "name": "P3",
          "profilePic":
          "https://lh3.googleusercontent.com/a-/AAuE7mCfQn-gP_FJZUUU4GC4aSU1km9t_e5PL6zsV-NwdA=k-s48",
          "category": ["cleaning"],
          "rating": 5,
          "bg": Colors.blue
        }
      ];
      List filteredData = [];
    
      void onTapped(int index) {
        setState(() {
          _selectedIndex = index;
        });
        pageController.jumpToPage(index);
      }
    
      void tappedCategory(int index) {
        _selectedCategoryIndex = index;
        _selectedUserType = array[index];
        _filterData();
      }
    
      @override
      void initState() {
        super.initState();
        _filterData();
      }
    
      _filterData() {
        print(_selectedUserType);
        filteredData =  data.where((element) => element["category"].contains(_selectedUserType)).toList();
        print(filteredData);
        setState(() {});
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: PageView(
                      controller: pageController,
                      children: [
                        SafeArea(
                          child: Column(
                              mainAxisAlignment: MainAxisAlignment.start,
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                            Padding(
                              padding:  EdgeInsets.symmetric(vertical: 5),
                              child: Container(
                                // color: Colors.purple,
                                  // margin: const EdgeInsets.only(top: 45, bottom: 15),
                                  padding: const EdgeInsets.only(left: 10, right: 10),
                                  child: Row(
                                      children: [
                                        Expanded(
                                          child: Column(
                                            crossAxisAlignment: CrossAxisAlignment.start,
                                              children:  [
                                            Text("Bengaluru",
                                              style: TextStyle(
                                                color: APP_COLOR.mainColor,
                                              ),
                                            ),
                                            Text("R.T Nagar")
                                          ]),
                                        ),
                                        customContainer(iconData: Icons.search,),
                                        SizedBox(width: 10,),
                                        customContainer(iconData: Icons.notifications,),
                                      ])),
                            ),
                            Expanded(
                            child: SingleChildScrollView(
                              child: Column(
                                children: [
    
                                  Padding(
                                    padding:  EdgeInsets.symmetric(vertical: 10,horizontal: 10),
                                    child: Align(
                                      alignment: Alignment.centerLeft,
                                      child:
                                      Text(
                                        'Popular Services',
                                      ),
                                    ),
                                  ),
                                  Container(
                                    height: MediaQuery.of(context).size.height / 12,
                                    child: ListView(
                                      shrinkWrap: true,
                                      scrollDirection: Axis.horizontal,
                                      children: List<Widget>.generate(
                                          array.length, // place the length of the array here
                                          (int index) {
                                            return Container(
                                              margin: const EdgeInsets.all(2.0),
                                              child: GestureDetector(
                                                onTap: () {
                                                  tappedCategory(index);
                                                },
                                                child: Chip(label: Text(array[index])),
                                              ),
                                            );
                                          }).toList(),
                                    ),
                                  ),
                                  Container(
                                    height: MediaQuery.of(context).size.height / 6,
                                    child: ListView.builder(
                                      scrollDirection: Axis.horizontal,
                                      // physics: NeverScrollableScrollPhysics(),
                                      itemCount: filteredData.length,
                                      itemBuilder: (context, index) {
                                        var item = filteredData[index];
                                        return Padding(
                                          padding:  EdgeInsets.symmetric(horizontal: 10),
                                          child: Container(
                                            color: item['bg'],
                                            child: Center(
                                              child: Padding(
                                                padding:  EdgeInsets.symmetric(horizontal: 20),
                                                child: Text(item["name"].toString()),
                                              ),
                                            ),
                                          ),
                                        );
                                      },
                                      // This next line does the trick.
                                    ),
                                  ),
                                  Padding(
                                    padding:  EdgeInsets.symmetric(vertical: 10,horizontal: 10),
                                    child: Row(
                                      mainAxisAlignment:MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          'Popular Products',
                                        ),
                                        Align(
                                          alignment: Alignment.centerRight,
                                          child:
                                          Text(
                                            'View All',
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  Container(
                                    height: MediaQuery.of(context).size.height / 6,
                                    child: ListView.builder(
                                      scrollDirection: Axis.horizontal,
                                      itemCount: product_data.length,
                                      itemBuilder: (context, index) {
                                        var item = product_data[index];
                                        return Padding(
                                          padding:  EdgeInsets.symmetric(horizontal: 10),
                                          child: Container(
                                            color: item['bg'],
                                            child: Center(
                                              child: Padding(
                                                padding:  EdgeInsets.symmetric(horizontal: 60),
                                                child: Text(item["name"].toString()),
                                              ),
                                            ),
                                          ),
                                        );
                                      },
                                      // This next line does the trick.
                                    ),
                                  ),
                                  Padding(
                                    padding:  EdgeInsets.symmetric(vertical: 10,horizontal: 10),
                                    child: Row(
                                      mainAxisAlignment:MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          'Our Products',
                                        ),
                                        Align(
                                          alignment: Alignment.centerRight,
                                          child:
                                          Text(
                                            'View All',
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  Container(
                                    height: MediaQuery.of(context).size.height / 6,
                                    child: ListView.builder(
                                      scrollDirection: Axis.horizontal,
                                      itemCount: product_data.length,
                                      itemBuilder: (context, index) {
                                        var item = product_data[index];
                                        return Padding(
                                          padding:  EdgeInsets.symmetric(horizontal: 10),
                                          child: Container(
                                            color: item['bg'],
                                            child: Center(
                                              child: Padding(
                                                padding:  EdgeInsets.symmetric(horizontal: 60),
                                                child: Text(item["name"].toString()),
                                              ),
                                            ),
                                          ),
                                        );
                                      },
                                      // This next line does the trick.
                                    ),
                                  ),
                                  Padding(
                                    padding:  EdgeInsets.symmetric(vertical: 10,horizontal: 10),
                                    child: Row(
                                      mainAxisAlignment:MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          'New Products',
                                        ),
                                        Align(
                                          alignment: Alignment.centerRight,
                                          child:
                                          Text(
                                            'View All',
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  Container(
                                    height: MediaQuery.of(context).size.height / 6,
                                    child: ListView.builder(
                                      scrollDirection: Axis.horizontal,
                                      itemCount: product_data.length,
                                      itemBuilder: (context, index) {
                                        var item = product_data[index];
                                        return Padding(
                                          padding:  EdgeInsets.symmetric(horizontal: 10),
                                          child: Container(
                                            color: item['bg'],
                                            child: Center(
                                              child: Padding(
                                                padding:  EdgeInsets.symmetric(horizontal: 60),
                                                child: Text(item["name"].toString()),
                                              ),
                                            ),
                                          ),
                                        );
                                      },
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          )
                          ]),
                        ),
                        Container(color: Colors.blue,),
                        Container(color: Colors.white,),
                        Container(color: Colors.yellow,),
                        Container(color: Colors.blue,),
                        Container(color: Colors.white,),
                        Container(color: Colors.yellow,)
                      ],
                    ),
            bottomNavigationBar: BottomNavigationBar(
              items: const <BottomNavigationBarItem>[
                BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
                BottomNavigationBarItem(
                    icon: Icon(Icons.cleaning_services), label: 'Services'),
                BottomNavigationBarItem(
                    icon: Icon(Icons.local_convenience_store), label: 'Store'),
                BottomNavigationBarItem(
                    icon: Icon(Icons.account_balance_wallet), label: 'Wallet'),
                BottomNavigationBarItem(
                    icon: Icon(Icons.bookmarks), label: 'Bookmarked'),
                BottomNavigationBarItem(
                    icon: Icon(Icons.assessment), label: 'Current Orders'),
                BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
              ],
              currentIndex: _selectedIndex,
              selectedItemColor: APP_COLOR.mainColor,
              unselectedItemColor: Colors.grey,
              onTap: onTapped,
            ));
      }
    
      Widget customContainer({required IconData iconData}){
        return Container(
          width: 45,
          height: 45,
          padding: const EdgeInsets.only(left: 0, right: 0),
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(15),
              color: APP_COLOR.mainColor,),
          child:  Icon(
            iconData,
            color: Colors.white,
          ),
        );
      }
    
    }
    

    I've recently started the flutter journey so i might have asked a very basic question so it will be great if you can explain the changes as well taht you made so i can understand it better

  • Sachin Rajput
    Sachin Rajput 6 months
    by default selection on Chip is not working
  • Sachin Rajput
    Sachin Rajput 6 months
    and in my case isNotEmpty() didn't work but filteredData.iterator.moveNext() did
  • Sachin Rajput
    Sachin Rajput 6 months
    it worked for most of the things but still the default chip is not picking the selected color
  • Prabhakaran
    Prabhakaran 6 months
    that is because _selectedCategoryIndex is set as -1 on init. I edited the code and also cleaned the code as well. check that