GtheG
GtheG

Reputation: 11

Flutter : setState outside

I'm new to Flutter and I just want to understand something about stateful widget. Here's a simple code that works perfectly just by switching the text color from red to blue when clicking on a button :

import 'package:flutter/material.dart';

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Color myColor = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("My app")),
        body: Column(
          children: [
            Text(
              "Just a simple text",
              style: TextStyle(color: myColor),
            ),
            FloatingActionButton(
                onPressed: () {
                  setState(() {
                    myColor =
                        (myColor == Colors.red) ? Colors.blue : Colors.red;
                  });
                  print(myColor);
                },
                child: Icon(Icons.home)),
          ],
        ));
  }
}

My question is : if I get the column outside the stateful widget and call it as a component, how and where should I rewrite the setState function ? I begin with this code and I don't know how to continue :

import 'package:flutter/material.dart';

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Color myColor = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("My app")),
        body: HomePage());
  }
}

Column HomePage()
{
return Column(
          children: [
            Text(
              "Just a simple text",
              style: TextStyle(color: myColor), // SHOULD I NOW INJECT myColor AS A PARAMETER OF HomePage ?
            ),
            FloatingActionButton(
                onPressed: () {print("WHERE TO PUT THE setState FUNCTION NOW ???")},
                child: Icon(Icons.home)),
          ],
        );
}

Upvotes: 0

Views: 3648

Answers (4)

Sam Chen
Sam Chen

Reputation: 8857

You can use callback functions:

  • VoidCallback: for notifying use, no parameters passing.

  • Function(T): for passing parameters.


This is a simple example of using VoidCallback for adding the counter:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  
  void _incrementCounter() {                          //function will be called
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ...,
      body: ListView(
        children: [
          _itemView(_incrementCounter),               //pass in the target function
        ],
      ),
    );
  }

  Widget _itemView(VoidCallback onAddClicked) {       //use "Function(T)" if need to pass parameters
    return Column(
      children: [
        Text('Name: Sam'),
        Text('Title: Flutter Developer'),
        MaterialButton(
          child: Text('Add'),
          onPressed: () {
            onAddClicked();                           //invoke callback function
          },
        ),
      ],
    );
  }
}

Upvotes: 0

Ivo
Ivo

Reputation: 23164

If you insist of having the HomePage() function outside the class you could do this for example:

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Color myColor = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("My app")),
        body: HomePage(myColor, changeColor));
  }
  
  void changeColor(Color color) {
    setState((){
      myColor = color;
    });
  }
}

Column HomePage(Color color, ValueSetter<Color> change)
{
    return Column(
      children: [
        Text(
          "Just a simple text",
          style: TextStyle(color: color),
        ),
        FloatingActionButton(
            onPressed: () { change(Colors.blue);},
            child: Icon(Icons.home)),
      ],
    );
}

Upvotes: 1

Anandh Krishnan
Anandh Krishnan

Reputation: 5984

Here's a example class for how to pass data from one class to another class

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'main1.dart';

void main() {
  runApp(MaterialApp(
    home: Modalbtn(),
  ));
}

class Modalbtn extends StatefulWidget {
  @override
  _ModalbtnState createState() => _ModalbtnState();
}

class _ModalbtnState extends State<Modalbtn> {
  String value = "0";
  // Pass this method to the child page.
  void _update(String newValue) {
    setState(() => value = newValue);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            IconButton(
              onPressed: () {
                showModalBottomSheet(
                    context: context,
                    builder: (BuildContext context) {
                      return Container(
                        height: 200,
                        child: Column(
                          children: [StatefulModalbtn(update: _update)],
                        ),
                      );
                    });
              },
              icon: Icon(Icons.add),
              iconSize: 20,
            ),
            Text(
              value,
              style: TextStyle(fontSize: 40),
            ),
          ],
        ),
      ),
    );
  }
}

import 'package:flutter/material.dart';

class StatefulModalbtn extends StatelessWidget {
  final ValueChanged<String> update;
  StatefulModalbtn({required this.update});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => update("100"), // Passing value to the parent widget.

      child: Text('Update (in child)'),
    );
  }
}

Upvotes: 0

Abdallah Abdel Aziz
Abdallah Abdel Aziz

Reputation: 676

Your HomePage() is just a function that returns a Column, so you can just include it within the _MyWidgetState class to be able to access the state directly, and call the setState method, like that:

import 'package:flutter/material.dart';

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Color myColor = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("My app")),
        body: HomePage());
  }


  Column HomePage(){
    return Column(
      children: [
        Text(
          "Just a simple text",
          style: TextStyle(color: myColor), // SHOULD I NOW INJECT myColor AS A PARAMETER OF HomePage ?
        ),
        FloatingActionButton(
            onPressed: () {
              setState(() {
                myColor = Colors.amber;
              });
            },
            child: Icon(Icons.home)),
      ],
    );
  }
}

Upvotes: 1

Related Questions