skip to Main Content

I created a card logic using ListView.separated in Flutter. What I want to implement here is, the current date is implemented in gray. However, the issue lies in the logic for changing the card color only for the clicked dates.

This is my code:

 Container date_card(BuildContext context) {
    return Container(
        height: MediaQuery.of(context).size.height * 0.13,
        width: MediaQuery.of(context).size.width * 1,
        child: ListView.separated(
          scrollDirection: Axis.horizontal,
          itemBuilder: (BuildContext context, int index) {
            // Today date
            DateTime currentDate = DateTime.now();
            DateTime startOfWeek =
                currentDate.subtract(Duration(days: currentDate.weekday + 1));

            DateTime itemDate = startOfWeek.add(Duration(days: index));
            String formattedDate = DateFormat('d').format(itemDate);
            String formattedDay = DateFormat('E').format(itemDate);


            bool isToday =
                formattedDate == DateFormat('d').format(currentDate) &&
                    formattedDay == DateFormat('E').format(currentDate);
        .
            int selectedCardIndex = -1;
            bool isSelected = selectedCardIndex == index;
            return InkWell(
              onTap: () {
                setState(() {
                  selectedCardIndex = index;
                  selectedCardIndex > 0 ? isSelected : false;
                });
              },
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 20),
                child: Card(
                  elevation: 2,
                  color: isToday
                      ? Color(0xff9a9a9a)
                      : isSelected
                          ? Colors.black
                          : Color(0xffF8F8F8),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10),
                  ),
                  child: Container(
                    height: MediaQuery.of(context).size.height * 0.1,
                    width: MediaQuery.of(context).size.width * 0.12,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        Text(
                          formattedDate,
                          style: TextStyle(
                            fontSize: 18,
                            color: isToday || isSelected
                                ? Colors.white
                                : Colors.black,
                          ),
                        ),
                        Text(
                          formattedDay.toUpperCase(),
                          style: TextStyle(
                            fontSize: 10,
                            color: isToday
                                ? Colors.white
                                : isSelected
                                    ? Colors.black
                                    : Color(0xff8EA0B6),
                          ),
                        ),
                        Text(
                          (isToday && isSelected) ? '˚' : '',
                          style: TextStyle(color: Colors.white),
                        )
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
          separatorBuilder: (BuildContext context, int index) =>
              SizedBox(width: 4),
          itemCount: 30,
        ));
  }

I used a regular expression, and the part I focused on is the onTap section.
Through this part, I made it return true when the value is less than 0, and I intended to give black color and white text only to those where isSelected is true.

 onTap: () {
                setState(() {
                  selectedCardIndex = index;
                  selectedCardIndex > 0 ? isSelected : false;
                });
...

color: isToday
                      ? Color(0xff9a9a9a)
                      : isSelected
                          ? Colors.black
                          : Color(0xffF8F8F8),
...

color: isToday
                                ? Colors.white
                                : isSelected
                                    ? Colors.black
                                    : Color(0xff8EA0B6),
                          ),
                        ),
                        Text(
                          (isToday && isSelected) ? '˚' : '',
                          style: TextStyle(color: Colors.white),
                        )

I attempted to use a regular expression for the conditional statement, but all attempts failed. I want the card to change to a black background when clicked, and return to its original state when clicked again. How can I achieve this? Please provide advice.

2

Answers


  1. You are declaring all variables within the function which is pointless because after a setState it will just go to the line

    int selectedCardIndex = -1;
    

    again. So you need to declare it outside the function.

    Also, this line:

    selectedCardIndex > 0 ? isSelected : false;
    

    does nothing at all. You are saying it’s returning a value but it’s not. Maybe you are thinking of kotlin where the last expression in a block is the return value, this doesn’t happen in dart. But it wouldn’t matter anyway because you can’t return any values from a setState.

    I’m not entirely sure if you needed that only one item is selectable or more, but if it’s just one then as I said you need to declare selectedCardIndex outside the function and you can change the onTap to

              onTap: () {
                setState(() {
                  selectedCardIndex = isSelected ? -1 : index;
                });
              },
    

    If you want to able to select multiple you could use a set instead for example, so declare

    Set<int> selectedIndexes = {};
    

    (outside the function) and this as onTap

              onTap: () {
                setState(() {
                  if (selectedIndexes.contains(index)){
                    selectedIndexes.remove(index);
                  } else {
                    selectedIndexes.add(index);
                  }
                });
              },
    

    and change isSelected to

            bool isSelected = selectedIndexes.contains(index);
    
    Login or Signup to reply.
  2. Use this code I have tried it, and it is working according to my understanding let me know if I got the logic wrong.

    class MyTiles extends StatefulWidget {
      const MyTiles({super.key});
    
      @override
      State<MyTiles> createState() => _MyTilesState();
    }
    
    class _MyTilesState extends State<MyTiles> {
      Container date_card(BuildContext context ,List<int> selectedCards ) {
    
        return Container(
            height: MediaQuery.of(context).size.height * 0.13,
            width: MediaQuery.of(context).size.width * 1,
            child: ListView.separated(
              scrollDirection: Axis.horizontal,
              itemBuilder: (BuildContext context, int index) {
                // Today date
                DateTime currentDate = DateTime.now();
                DateTime startOfWeek =
                    currentDate.subtract(Duration(days: currentDate.weekday + 1));
    
                DateTime itemDate = startOfWeek.add(Duration(days: index));
                String formattedDate = DateFormat('d').format(itemDate);
                String formattedDay = DateFormat('E').format(itemDate);
    
                bool isToday =
                    formattedDate == DateFormat('d').format(currentDate) &&
                        formattedDay == DateFormat('E').format(currentDate);
    
                int selectedCardIndex = -1;
                bool isSelected = selectedCardIndex == index;
                return InkWell(
                  onTap: () {
                    setState(() {
                      selectedCardIndex = index;
                      selectedCardIndex > 0 ? isSelected : false;
    
                      if (selectedCards.contains(index)) {
                        selectedCards.remove(index);
                      } else {
                        selectedCards.add(index);
                      }
                      setState(() {
    
                      });
                      print(selectedCards);
    
                    });
                  },
                  child: Padding(
                    padding: const EdgeInsets.symmetric(vertical: 20),
                    child: Card(
                      elevation: 2,
                      color: selectedCards.contains(index) ?  Colors.black : isToday
                          ? Color(0xff9a9a9a)
                          : isSelected
                              ? Colors.black
                              : Color(0xffF8F8F8),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10),
                      ),
                      child: Container(
                        height: MediaQuery.of(context).size.height * 0.1,
                        width: MediaQuery.of(context).size.width * 0.12,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: [
                            Text(
                              formattedDate,
                              style: TextStyle(
                                fontSize: 18,
                                color: selectedCards.contains(index) ?  Colors.white : isToday || isSelected
                                    ? Colors.white
                                    : Colors.black,
                              ),
                            ),
                            Text(
                              formattedDay.toUpperCase(),
                              style: TextStyle(
                                fontSize: 10,
                                color: selectedCards.contains(index) ?  Colors.white :isToday
                                    ? Colors.white
                                    : isSelected
                                        ? Colors.black
                                        : Color(0xff8EA0B6),
                              ),
                            ),
                            Text(
                              (isToday && isSelected) ? '˚' : '',
                              style: TextStyle(color: Colors.white),
                            )
                          ],
                        ),
                      ),
                    ),
                  ),
                );
              },
              separatorBuilder: (BuildContext context, int index) =>
                  SizedBox(width: 4),
              itemCount: 30,
            ));
      }
    
      dynamic mySelectedCards= [1];
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Column(
              children: [
                date_card(context,mySelectedCards),
              ],
            ),
          ),
        );
      }
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search