Ben Ajax
Ben Ajax

Reputation: 740

Single Selection for ListView Flutter

I am trying to implement a listView single selection in my app such that once an item in the list is tapped such that pressed item color state is different from the others. I have done all I know but it does not work well. The problem is that even though my implementation updates each item state when pressed, it doesn't reset the others to their initial state.

expected output

class BoxSelection{
  bool isSelected;
  String title;
  String options;
  BoxSelection({this.title, this.isSelected, this.options});
}


class _AddProjectState extends State<AddProject> {
  List<BoxSelection> projectType = new List();
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    projectType
        .add(BoxSelection(title: "Building", isSelected: false, options: "A"));
    projectType
        .add(BoxSelection(title: "Gym House", isSelected: false, options: "B"));
    projectType
        .add(BoxSelection(title: "School", isSelected: false, options: "C"));
  }

  child: ListView.builder(
                      itemCount: projectType.length,
                      itemBuilder: (BuildContext context, int index) {
                        return GestureDetector(
                          onTap: () {
                            setState(() {
       //here am trying to implement single selection for the options in the list but it don't work well
                              for(int i = 0; i < projectType.length; i++) {
                                if (i == index) {
                                  setState(() {
                                    projectType[index].isSelected = true;
                                  });
                                } else {
                                  setState(() {
                                    projectType[index].isSelected = false;
                                  });
                                }
                              }
                            });
                          },
                          child: BoxSelectionButton(
                            isSelected: projectType[index].isSelected,
                            option: projectType[index].options,
                            title: projectType[index].title,
                          ),
                        );
                      },
                    ),

Upvotes: 8

Views: 10426

Answers (1)

Claudio Redi
Claudio Redi

Reputation: 68400

Your problem is that you're using index to access projectType elements but you should be using i

if (i == index) {
    setState(() {
    projectType[i].isSelected = true;
    });
} else {
    setState(() {
    projectType[i].isSelected = false;
    });
}  

In any case I think your code can be improved since it's not as efficient as it could be. You're iterating over the entire list and calling setState twice in every iteration, recreating the widget tree a lot of times unnecessarily when it can be done in one shoot.

  1. Save your current selection in a class level variable

    BoxSelection _selectedBox
    
  2. Simplify your code to act directly over the current selection insted of iterating over the entire list

     onTap: () =>
       setState(() {
         if (_selectedBox != null) {
             _selectedBox.isSelected = false;
         }
         projectType[index].isSelected = !projectType[index].isSelected;
         _selectedBox = projectType[index];
       });   
    

Upvotes: 9

Related Questions