у вас должно быть значение isSelected для каждого отдельного элемента в списке, а затем, когда пользователь нажимает на один из элементов в списке, вы меняете значение isSelected только для индексированного элемента записи и в инструкции построения, которую вы следует выполнить действие на основе значения isSelected переданного в index
вот пример:
![enter image description here](https://i.stack.imgur.com/hxeuK.png)
class MyListWidgetState extends State<MyListWidget> {
List<String> items = ["A", "B", "C", "D", "E", "F"];
Map<int, bool> itemsSelectedValue = Map();
@override
Widget build(BuildContext context) {
return new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
bool isCurrentIndexSelected = itemsSelectedValue[index] == null
? false
: itemsSelectedValue[index];
Container contianer;
if (isCurrentIndexSelected) {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
items[index],
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
items[index],
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
print("${!isCurrentIndexSelected}");
itemsSelectedValue[index] = !isCurrentIndexSelected;
setState(() {
print("OnClick : $index + ${itemsSelectedValue[index]}");
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: contianer,
),
);
});
}
}
или вы можете создать виджет StateFull, который будет иметь собственное значение isSelected для каждого элемента вашего списка, как показано в примере ниже:
List<String> items = [
"A",
"B",
"C",
"D",
"E",
"F",
"D",
"J",
"K",
"L",
"M",
"P"
];
class SampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return new SelectableWidget(
new SelectableWidgetViewModel(
items[index],
isSelected: false,
),
);
},
)),
);
}
}
class SelectableWidget extends StatefulWidget {
final SelectableWidgetViewModel viewModel;
SelectableWidget(this.viewModel);
@override
State<StatefulWidget> createState() {
return SelectableWidgetState();
}
}
class SelectableWidgetState extends State<SelectableWidget> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
Container container;
if (widget.viewModel.isSelected) {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
setState(() {
widget.viewModel.isSelected = !widget.viewModel.isSelected;
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: container,
),
);
}
}
class SelectableWidgetViewModel {
bool isSelected;
String title;
SelectableWidgetViewModel(this.title, {this.isSelected = false});
}
я думаю, что второй вариант лучше по соображениям производительности