简体   繁体   中英

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,)
                          ],
                        ),
                      ),
                    ),

I've created your app as a test version. All you need to do is inject your widget in the //put your widget here!!!!! section. Also for testing this right now as a demo, you can paste the code on dartpad and select "New" -> "Flutter" -> Paste Code: https://dartpad.dev 在此处输入图像描述

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowtappedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: CustomCheckboxGrid(),
        ),
      ),
    );
  }
}

class CustomCheckboxGrid extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _CustomCheckboxGridState();
  }
}

class _CustomCheckboxGridState extends State<CustomCheckboxGrid> {
 
  
 int tapped_index = 0;

List card_names = [
  'Maintaining healthy relationships',
  'Being happier and more content in life',
  'Work life balance',
  'Personal Growth',
  'Stress',
  'Mental health',
];

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: GridView.builder(
      padding: const EdgeInsets.all(16),
      itemCount: card_names.length,
      itemBuilder: (BuildContext context, int index) {
        return buildCard(index);
      },
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
    ),
  );
}

Widget buildCard(int index) {
  bool tapped = index == tapped_index;
  String current_name = card_names[index];
  return GestureDetector(
    onTap: () {
      setState(() {
        print("Tapped index: ${index}");
        tapped_index = index;
      });
    },
    child: Stack(
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.all(14),
          child: 
            //put your widget here!!!!!
            //-----------------------------------
            Card(
            color: tapped ? Colors.orange : Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16),
            ),
            child: Container(
              child: Center(child: Text(current_name)),
            ),
          ),
            //-----------------------------------
        ),
        Positioned(
          top: 14,
          right: 14,
          child: Offstage(
            offstage: !tapped,
            child: Container(
              decoration: BoxDecoration(
                  color: Colors.white,
                  border: Border.all(width: 2),
                  shape: BoxShape.circle),
              child: Icon(
                Icons.check,
                color: Colors.green,
              ),
            ),
          ),
        ),
      ],
    ),
  );
}
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM