Home > Net >  Dynamic state in Flutter widget
Dynamic state in Flutter widget

Time:03-17

I have a logic/conceptual problem that I don't know how to solve.

From API I get an array of objects with dynamic length:

data = [{price: 10, label: 'a'}, {price: 2, label: 'd'}, {price: 5, label: 'b'}]

Each of this data corresponds (in UI) to a quantity selector so something like this:

a: - 0   (price: 10)
d: - 0   (price: 2)
b: - 0   (price: 5)

And then I need to compute the total price.

User can increase and decrease the quantity of each item. For example the app could be in these states:

a: - 1   (price: 10)
d: - 1   (price: 2)
b: - 0   (price: 5)
total: 12

a: - 2   (price: 10)
d: - 1   (price: 2)
b: - 3   (price: 5)
total: 37

a: - 0   (price: 10)
d: - 4   (price: 2)
b: - 0   (price: 5)
total: 8

...

The problem here is that I don't know how to structure the Widget state.

I created this widget:

class QuantityUI extends StatefulWidget {
  const QuantityUI({
    Key? key,
    required this.name,
    required this.price,
    required this.counter,
    required this.add,
    required this.remove,
  }) : super(key: key);

  final String name;
  final double price;
  final int counter;
  final VoidCallback add;
  final VoidCallback remove;

  @override
  _QuantityUI createState() => _QuantityUI();
}

class _QuantityUI extends State<QuantityUI> {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        IconButton(icon: const Icon(Icons.remove), onPressed: widget.counter == 0 ? null : widget.remove),
        Text(widget.counter.toString()),
        IconButton(icon: const Icon(Icons.add), onPressed: widget.add),
        Text(widget.name.capitalize()),
        Text('${widget.price}€')
      ],
    );
  }
}

and I use it in the parent widget this way:

Column(
  children: data.map((Datum d) {
    return QuantityUI(
      name: d.label,
      price: d.price,
      counter: priceCounter, // <-- this should be a variable in my state
      add: () => setState(() => priceCounter  ),
      remove: () => setState(() => priceCounter--),
    );
  }).toList(),
)

This should be dynamic. How can I create n variables in the state, one for each data item?

CodePudding user response:

You should add counter for each of your data items and change that counter on add and remove callbacks. Here is the working solution:

class Test extends StatefulWidget {
  const Test({Key? key}) : super(key: key);

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  late List data = [
      {"price": 10, "label": 'a'},
      {"price": 2, "label": 'd'},
      {"price": 5, "label": 'b'}
    ];
  @override
  void initState() {
    super.initState();
    data = data.map((e) {
      e['counter'] = 0;
      return e;
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Column(
        children: data.map((d) {
          return QuantityUI(
            name: d["label"] as String,
            price: (d["price"] as int).toDouble(),
            counter: (d["counter"]) as int,
            add: () => setState(() => d["counter"]  ),
            remove: () => setState(() => d["counter"]--),
          );
        }).toList(),
      )),
    );
  }
}
  • Related