Search code examples
fluttercountergetter-setterstatefulwidgetflutter-state

Get the value of an integer from a stateful widget from another class in flutter


Learning Flutter and I am building a counter that I would like to use for a cart. I have a problem retrieving the integer value of the counter stateful widget I created and i'd like a Text to update itself with the value of the Counter.

Here is the Code for the Counter

import 'package:flutter/material.dart';

class TheCounter extends StatefulWidget {
  int counter = 0;
  int get counterValue => counter;

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

class _TheCounterState extends State<TheCounter> {
  void increaseCounter() {
    setState(() {
      if (widget.counter >= 0) {
        widget.counter++;
      }
    });
  }

  void decreaseCounter() {
    setState(() {
      if (widget.counter > 0) {
        widget.counter--;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        IconButton(icon: Icon(Icons.add), onPressed: increaseCounter),
        Text('${widget.counter}'),
        IconButton(icon: Icon(Icons.remove), onPressed: decreaseCounter)
      ],
    );
  }
}

And here is the main.dart file

import 'package:counter/counter.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(Count());
}

class Count extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    int counting = TheCounter().counterValue;
    return MaterialApp(
      title: 'Counter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Counter Test'),
        ),
        body: Column(
          children: [
            TheCounter(),
            Text('$counting'),
            TheCounter(),
            TheCounter(),
          ],
        ),
      ),
    );
  }
}

I'd like the Text to update itself with the value of the counter whenever the add or remove button is clicked. What do I do to achieve that?


Solution

  • Firstly, we need to make a decision where the update will happen. In this case the Count widget text need to update. Therefore, need to convert this as StatefulWidget.

    Next thing is how we can retrieve counter from TheCounter widget. You can use callback method, or state management package like provider, riverpod, bloc etc. You can check the doc

    Here I am using a function that will get update value on Count whenever the count value change on TheCounter widget.

    
    void main() {
      runApp(MaterialApp(title: 'Counter', home: Count()));
    }
    
    class Count extends StatefulWidget {
      const Count({Key? key}) : super(key: key);
    
      @override
      State<Count> createState() => _CountState();
    }
    
    class _CountState extends State<Count> {
      int initNumberOfCounter = 4;
    
      late List<int> countersValue = List.generate(initNumberOfCounter, (index) => 0);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Counter Test'),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              setState(() {
                countersValue.add(0);
              });
            },
          ),
          body: Column(
            children: [
              Expanded(
                child: ListView.builder(
                  itemCount: countersValue.length,
                  itemBuilder: (context, index) {
                    return Row(
                      // mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        TheCounter(
                          initCountValue: countersValue[index],
                          countValueCallback: (v) {
                            setState(() {
                              countersValue[index] = v;
                            });
                          },
                        ),
                        const SizedBox(
                          width: 40,
                        ),
                        Text("${countersValue[index]}"),
                      ],
                    );
                  },
                ),
              )
            ],
          ),
        );
      }
    }
    
    class TheCounter extends StatefulWidget {
      final Function(int) countValueCallback;
      final int initCountValue;
      const TheCounter({
        Key? key,
        required this.countValueCallback,
        this.initCountValue = 0,
      }) : super(key: key);
    
      @override
      _TheCounterState createState() => _TheCounterState();
    }
    
    class _TheCounterState extends State<TheCounter> {
      ///this use within the current state
      late int counter;
    
      @override
      void initState() {
        super.initState();
    
        ///set counter value for the 1st time
        counter = widget.initCountValue;
      }
    
      void increaseCounter() {
        setState(() {
          if (counter >= 0) {
            counter++;
          }
        });
    
        /// back to parent widget
        widget.countValueCallback(counter);
      }
    
      void decreaseCounter() {
        setState(() {
          if (counter > 0) {
            counter--;
          }
        });
        widget.countValueCallback(counter);
      }
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            IconButton(icon: Icon(Icons.add), onPressed: increaseCounter),
            Text('${counter}'),
            IconButton(icon: Icon(Icons.remove), onPressed: decreaseCounter)
          ],
        );
      }
    }