Esam Olwan
Esam Olwan

Reputation: 362

How can I select one item at a time in a ListView.builder?

I've a stateful widget called Emotion that displays an icon and text underneath it , and the icon turns green and the text is displayed after the icon has been tapped. I also have a listview displaying 'Emotions' in my screen Container as follows :

Expanded(
                child: ListView.builder(
                    itemExtent: 100,
                    itemCount: moodIcons.length,
                    shrinkWrap: true,
                    scrollDirection: Axis.horizontal,
                    itemBuilder: (context, index) {
                      return Emotions(
                        icon: moodIcons[index],
                        textIcon: textIcons[index],
                      );
                    }),
              )
class Emotions extends StatefulWidget {
  final IconData icon;
  final String textIcon;

  const Emotions({Key key, this.icon, this.textIcon}) : super(key: key);
  @override
  _EmotionsState createState() => _EmotionsState();
}

class _EmotionsState extends State<Emotions> {
  bool _isPressed = false;
  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      duration: Duration(milliseconds: 350),
      curve: Curves.easeIn,
      child: Column(
        children: [
          GestureDetector(
            onTap: () {
              setState(() {
                _isPressed = !_isPressed;
              });
            },
            child: Icon(
              widget.icon,
              size: 40,
              color: _isPressed ? Colors.green : Colors.black,
            ),
          ),
          Text(
            widget.textIcon,
            style: TextStyle(
                color: _isPressed
                    ? Colors.black.withOpacity(0.7)
                    : Colors.black.withOpacity(0.0)),
          ),
        ],
      ),
    );
  }
}

I've used the following 2 lists :

List<IconData> moodIcons = <IconData>[
    Icons.mood_bad,
    Icons.sentiment_very_dissatisfied,
    Icons.sentiment_dissatisfied,
    Icons.sentiment_satisfied,
    Icons.sentiment_very_satisfied
  ];
  List<String> textIcons = <String>[
    "bad mood",
    "very sad",
    "sad",
    "happy",
    "very happy"
  ];

How can I make this list of Emotion widgets select only one item at a time?

Upvotes: 1

Views: 1429

Answers (1)

Sergio Pardo
Sergio Pardo

Reputation: 792

If you are looking for an answer embedded on the flutter framework; I do not know any related to the ListView or any of it's constructors. The ListView Widget is made to display the children passed as parameter and nothing more like changing the state inside those elements.

My suggestion to you is have the same list of elements as objects instead of just plain strings. In those objects you could have the String, the icon and a boolean atributte that describes if the item is selected or not. On tap, you change the list to update the respective items on the boolean atribute and if you have that list on the state it will refresh the list and show only one item selected.

Object:

class MyObject {
   IconData icon;
   bool selected;
   String text;

   MyObject(this.icon, this.selected, this.text);
}

List:

List<MyObject> moodIcons = <MyObject>[
    MyObject(Icons.mood_bad, "Bad mood", false),
    MyObject(Icons.sentiment_very_dissatisfied, "Very sad", false),
];

ListView.builder:

ListView.builder(
    itemCount: moodIcons.length,
    shrinkWrap: true,
    scrollDirection: Axis.horizontal,
    itemBuilder: (context, index) {
        Color iconColor;
        if(moodIcons.selected) {
            iconColor = Colors.green;
        } else {
            iconColor = Colors.gray;
        }

        return GestureDetector(
            child: Emotions(
                icon: Icon(
                    moodIcons[index].icon,
                    color: iconColor,
                ),
                textIcon: textIcons[index].text,
            ),
            onTap: () {
                for(int i = 0; i < moodIcons.length ; i++) {
                   if(i == index) {
                       moodIcons[i].selected = !moodIcons[i].selected;
                   } else if(moodIndex[i].selected) {
                       moodIcons[i].selected = false;
                   }
                }
                setState(() {});
            }
        );
    }),

Upvotes: 2

Related Questions