как сделать динамический счетчик?
делаю корзину на flutter. Но, столкнулся с проблемой. По задумке, юзер может добавить количество товара из корзины. Но, из-за того, что я использую одну переменную, то счетчик увеличивается/уменьшается везде сразу. Как это исправить? PS: Я не могу знать, сколько будет товара, его добавляет сам пользователь
Вот мой код - Сохранение состояния -
int value = 1;
inc() {
setState(() {
value++;
});
}
dec() {
setState(() {
value--;
});
}
Отображение -
Expanded(
child: ListView.builder(
controller: controller,
padding: EdgeInsets.all(5),
itemCount: HomeBody.shoppingBasketHeader!.length,
itemBuilder: (context, index) {
if (index < HomeBody.shoppingBasketHeader!.length) {
return Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(2),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black))
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Container(
width: 150,
child: Image.network('http://10.0.2.2:1337${HomeBody.shoppingBasketImage?[index]}'),
)
],
),
Column(
children: [
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${HomeBody.shoppingBasketHeader?[index]}', style: TextStyle(fontSize: 15),),
),
],
),
),
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${HomeBody.shoppingBasketPrice?[index]}', style: TextStyle(fontSize: 15),),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: IconButton(onPressed: () {inc();}, icon: Icon(Icons.add)),
),
Container(
child: Text('$value'),
),
Container(
child: IconButton(onPressed: () {dec();}, icon: Icon(Icons.remove)),
)
],
)
],
),
],
),
);
} else {
return Padding(padding: EdgeInsets.symmetric(
vertical: 10),
child: Center(
child: Text('Список полностью загружен!'),
),
);
}
}
)
Ответы (1 шт):
Автор решения: ddo5
→ Ссылка
Для вашего примера могу предложить решение c ValueNotifier, который позволяет перестраивать не весь виджет, а лишь ту часть, которую вам понадобится обновлять.
- Генерируем список с объектами
ValueNotifierперед методомWidget build():
final valueNotifiers = List.generate(
HomeBody.shoppingBasketHeader!.length,
(_) => ValueNotifier<int>(1),
);
- Контент, который должны перестраивать, оборачиваем виджетом
ValueListenableBuilder:
ValueListenableBuilder<int>(
valueListenable: valueNotifiers[index],
builder: (context, counter, child) {
return Text('$counter');
},
)
- Теперь
incиdecбудут выглядеть так:
inc(int index) {
counterNotifiers[index].value++;
}
dec(int index) {
counterNotifiers[index].value--;
}
- Не забываем уничтожить наши объекты:
@override
void dispose() {
controller.dispose();
for (final notifier in counterNotifiers) {
notifier.dispose();
}
super.dispose();
}
Полный пример может выглядеть так:
class BasketPage extends StatefulWidget {
const BasketPage({Key? key}) : super(key: key);
@override
State<BasketPage> createState() => _BasketPageState();
}
class _BasketPageState extends State<BasketPage> {
final controller = ScrollController();
inc(int index) {
counterNotifiers[index].value++;
}
dec(int index) {
counterNotifiers[index].value--;
}
final counterNotifiers = List.generate(
HomeBody.shoppingBasketHeader!.length,
(_) => ValueNotifier<int>(1),
);
@override
void dispose() {
controller.dispose();
for (final notifier in counterNotifiers) {
notifier.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Корзина'),
),
body: ListView.builder(
controller: controller,
padding: EdgeInsets.all(5),
itemCount: HomeBody.shoppingBasketHeader!.length,
itemBuilder: (context, index) {
if (index < HomeBody.shoppingBasketHeader!.length) {
return Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(2),
decoration:
const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black))),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Container(
width: 150,
)
],
),
Column(
children: [
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(
' ${HomeBody.shoppingBasketHeader?[index]}',
style: TextStyle(fontSize: 15),
),
),
],
),
),
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(
' ${HomeBody.shoppingBasketPrice?[index]}',
style: TextStyle(fontSize: 15),
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: IconButton(
onPressed: () {
inc(index);
},
icon: Icon(Icons.add),
),
),
Container(
child: ValueListenableBuilder<int>(
valueListenable: counterNotifiers[index],
builder: (context, value, child) {
return Text('$value');
},
),
),
Container(
child: IconButton(
onPressed: () {
dec(index);
},
icon: Icon(Icons.remove),
),
)
],
),
],
),
],
),
);
} else {
return Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Center(
child: Text('Список полностью загружен!'),
),
);
}
},
),
);
}
}