Reputation: 285
What I'm trying to do
I have Choice class which includes a list like below.
class Choice {
Choice({this.title, this.selected});
final String title;
final IconData icon;
bool selected;
}
List<Choice> categoryChoices = <Choice>[
Choice(title: 'Highlights', selected: true),
Choice(title: 'Coming Up', selected: false),
Choice(title: 'England', selected: false),
Choice(title: 'Germany', selected: false),
Choice(title: 'Italy', selected: false),
Choice(title: 'Spain', selected: false),
Choice(title: 'France', selected: false),
Choice(title: 'Turkey', selected: false),
];
Also I have a ChoiceButton class which generates GestureDetectors based on the choice list above.
class ChoiceButton extends StatefulWidget {
ChoiceButton({this.choice, this.onPressed});
final Choice choice;
final Function onPressed;
@override
_ChoiceButtonState createState() => _ChoiceButtonState();
}
class _ChoiceButtonState extends State<ChoiceButton> {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
alignment: Alignment.center,
child: Text(
widget.choice.title,
style: kTextStyleButtonPrimary.copyWith(
fontSize: 16.0, fontWeight: FontWeight.normal),
),
decoration: BoxDecoration(
color: widget.choice.selected ? Colors.blue : Colors.white,
borderRadius: BorderRadius.circular(10.0),
border: Border.all(
color: Colors.blue,
),
),
height: 40.0,
width: 120.0,
),
onTap: widget.onPressed,
);
}
}
What is the problem
In my home screen, I put these gesture detectors in a scrollable row. When a gesture detector tapped, I'm changing the color. No problem, my code does all of these. The problem is, there shoulde be only one tapped GestureDetector at the moment. When user taps another, I should set all of others selected property as false. I'm using a map, but I can't find a way to reach other elements of the map to set their selected properties as false. What is the best way to do that kind of thing?
Padding(
padding: EdgeInsets.only(
left: 12.0, right: 12.0, top: 8.0, bottom: 2.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: categoryChoices.map((Choice choice) {
print(choice);
return Padding(
padding: EdgeInsets.only(
left: 4.0, right: 4.0, top: 2.0, bottom: 2.0),
child: ChoiceButton(
choice: choice,
onPressed: () {
//var index = categoryChoices.indexOf(choice);
setState(() {
choice.selected = true;
});
},
),
);
}).toList(),
Upvotes: 1
Views: 951
Reputation: 107231
You can do that by modifying your ChoiceButton implementation. You need to add an unique field in your Choice model (an integer id or something like that), here I'm assuming your title field as unique.
class ChoiceButton extends StatefulWidget {
ChoiceButton({this.choice, this.onPressed, this.selectedChoice});
final String selectedChoice; // Add this field to keep track of current selected choice value
final Choice choice;
final Function onPressed;
@override
_ChoiceButtonState createState() => _ChoiceButtonState();
}
class _ChoiceButtonState extends State<ChoiceButton> {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
alignment: Alignment.center,
child: Text(
widget.choice.title,
style: TextStyle(
fontSize: 16.0, fontWeight: FontWeight.normal),
),
decoration: BoxDecoration(
// The selection is made based on currently selected value
color: widget.selectedChoice == widget.choice.title ? Colors.blue : Colors.white,
borderRadius: BorderRadius.circular(10.0),
border: Border.all(
color: Colors.blue,
),
),
height: 40.0,
width: 120.0,
),
onTap: widget.onPressed,
);
}
}
And in your file (where you are going to use the choice button) declare a variable to keep track of selected value)
String selectedValue;
And now change your ChoiceButton initialising code to:
ChoiceButton(
choice: choice,
selectedChoice: selectedValue,
onPressed: () {
setState(() {
selectedValue = choice.title;
});
},
),
Upvotes: 1