Search code examples
flutterdartflutter-layoutandroid-gridview

How to make Flutter GridView change colors when tapped


I have asked this question previously but I am not receiving much help. I've created a GridView using GridView.count; however, I cannot get an indiviual container to change colors. The entire row changes if I click on any container within the row. I want to be able to change an individual container's color when it is tapped on, as well as have check mark appear on the top right corner of the container when selected.

(1) My Layout

(2) An Example of what I would like to happen

I'm very new to Flutter, so my code is not very optimal. I've tried making a list model as well but I have not had any luck with that. I'm attaching a portion of my code to show what I've done so far. Any help would be great :)

Widget build(BuildContext) {
    double _height = MediaQuery.of(context).size.height;
    final data = ModalRoute.of(context)!.settings;

    String retrieveString;

    if (data.arguments == null) {
      retrieveString = "empty";
    } else {
      retrieveString = data.arguments as String;
    }

    return Scaffold(
      resizeToAvoidBottomInset: false,

      backgroundColor: const Color(0xff31708c),

      body: Padding(
        padding: EdgeInsets.only(
          left: 30,
          right: 30,
          top: _height * 0.2),
          child: Column(
            children: <Widget>[
              Text('Hi $retrieveString! What all would you like to focus on?',
              style: GoogleFonts.montserrat(
                color: Colors.white70,
                fontSize: 19,
                fontWeight: FontWeight.w600
              ),
              textAlign: TextAlign.center,),
              const SizedBox(height: 9),
              Text("You can pick all that apply:",
              style: GoogleFonts.montserrat(
                color: Colors.white70,
                fontSize: 14.5,
                fontWeight: FontWeight.w600
              ),),
              const SizedBox(height: 9,),
                Column(children: [
                GridView.count(
                  primary: true,
                  shrinkWrap: true,
                  padding: const EdgeInsets.all(10),
                  childAspectRatio: 1.15,
                  crossAxisCount: 2,
                  crossAxisSpacing: 25,
                  mainAxisSpacing: 25,
                  children: <Widget>[
                    GestureDetector(
                      onTap: () {
                        setState(() {
                          _ContainerColor = _ContainerColor == Colors.white
                          ? Color(0xffa1d0e6)
                          : Colors.white;
                        });
                      },
                      child: Container(
                        padding: const EdgeInsets.all(8),
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(15),
                          border: Border.all(
                            color: const Color.fromARGB(255, 20, 83, 106),
                          width: 2.5),
                          color: _ContainerColor
                        ),
                        child: Column(
                          children: [
                            const Align(alignment: Alignment.topCenter,
                            child: Icon(MyFlutterApp.relationships,
                            color: Color(0xff31708c),
                            size: 45,),
                            ),
                            const SizedBox(height: 4,),
                            Text('Maintaining healthy relationships',
                            style: GoogleFonts.montserrat(
                              fontSize: 14,
                              fontWeight: FontWeight.w500,
                              color: const Color(0xff31708c)
                            ),
                            textAlign: TextAlign.center,)
                          ],
                        ),
                      ),
                    ),

Solution

  • From my understanding, you have to do allow users to have multi-select, because of the line

    You can pick all that apply:

    So here is a custom stateful widget that helps you to do multi-select, you can have your own widget child inside the gridview.

    class CustomPage extends StatefulWidget {
      const CustomPage({Key? key}) : super(key: key);
    
      @override
      State<CustomPage> createState() => _CustomPageState();
    }
    
    class _CustomPageState extends State<CustomPage> {
      String retrieveString = "";
      List selectedIndex = [];
      List dataItems = ['India', 'USA', 'Germany'];
    
      @override
      Widget build(BuildContext context) {
        double height = MediaQuery.of(context).size.height;
        final data = ModalRoute.of(context)!.settings;
    
        if (data.arguments == null) {
          retrieveString = "empty";
        } else {
          retrieveString = data.arguments as String;
        }
    
        return Scaffold(
            resizeToAvoidBottomInset: false,
            backgroundColor: const Color(0xff31708c),
            body: Padding(
                padding: EdgeInsets.only(left: 30, right: 30, top: height * 0.2),
                child: Column(children: <Widget>[
                  Text('Hi $retrieveString! What all would you like to focus on?'),
                  const SizedBox(height: 10),
                  const Text("You can pick all that apply:"),
                  const SizedBox(height: 10,),
                  Expanded(
                    child: GridView.builder(
                      scrollDirection: Axis.vertical,
                      primary: true,
                      shrinkWrap: true,
                      padding: const EdgeInsets.all(10),
                      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                          childAspectRatio: 1.15,
                          crossAxisCount: 2,
                          crossAxisSpacing: 25,
                          mainAxisSpacing: 25),
                      itemCount: dataItems.length,
                      itemBuilder: (context, index) {
                        return GestureDetector(
                          onTap: () {
                            setState(() {
                              if (selectedIndex.contains(index)) {
                                selectedIndex.remove(index);
                              } else {
                                selectedIndex.add(index);
                              }
                            });
                          },
                          child: Stack(
                            alignment: Alignment.topRight,
                            children: [
                              Container(
                                padding: const EdgeInsets.all(8),
                                decoration: BoxDecoration(
                                    borderRadius: BorderRadius.circular(15),
                                    border: Border.all(
                                        color:
                                            const Color.fromARGB(255, 20, 83, 106),
                                        width: 2.5),
                                    color: selectedIndex.contains(index)
                                        ? const Color(0xffa1d0e6)
                                        : Colors.white),
                                child: Center(
                                  child: Text(dataItems[index]),
                                ),
                              ),
                              selectedIndex.contains(index)
                                  ? Container(
                                      padding: const EdgeInsets.all(10),
                                      child: const CircleAvatar(
                                        child: Icon(Icons.check_outlined),
                                      ),
                                    )
                                  : Container()
                            ],
                          ),
                        );
                      },
                    ),
                  )
                ])));
      }
    }
    

    Hope it resolves your issue.