McDonal_11
McDonal_11

Reputation: 4075

Flutter: how to call setState() in onPressed() from separate Widget method

I am new to this Flutter

I am trying to change FlatButton text while onPressed. My page design in separate Widget method, so unable to add setState() in onPressed.

I have searched a lot. But, couldn't find. Kindly help me on this.

import 'package:flutter/material.dart';

int number = 10;

class SecondRoute extends StatelessWidget {
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Lists'),
        backgroundColor: new Color(0xFF000000),
      ),
      body: DynamicChange(),
    );
  }
}

class DynamicChange extends StatefulWidget {
  @override
  StateDynamic createState() => StateDynamic();
} // Class SecondRoute

class StateDynamic extends State<DynamicChange> {
  Widget build(BuildContext context) {
    return new Scaffold(
      body: thisScreenNeeds(),
    );
  }
}

Widget thisScreenNeeds() {
  return Container(
    margin: EdgeInsets.only(top: 100, left: 50),
      child: FlatButton(
    child: Text(
      number.toString(),
      textAlign: TextAlign.center,
      style: (TextStyle(
          fontWeight: FontWeight.bold, fontSize: 60, color: Colors.green)),
    ),
    onPressed: () {
       // Unable to add, setState(). Throwing error.
    },
  ));
}

Attempt 1

onPressed: () {
      // Error: The member 'setState' can only be used within instance members of subclasses
      StateDynamic().setState(() {
        number = number + 1;
   });
},

Attempt 2

class StateDynamic extends State<DynamicChange> {

.....
.........

void _incrementCounter() {
    setState(() {
      number++;
    });
  }

.....
.......

}

onPressed: StateDynamic()._incrementCounter,

// Run Time Error: 
   This happens when you call setState() on a State object for a 
   widget that hasn't been inserted into the widget tree yet. 
   It is not necessary to call setState() in the constructor, 
   since the state is already assumed to be dirty when it is 
   initially created.

Upvotes: 6

Views: 18944

Answers (1)

Mehmet Esen
Mehmet Esen

Reputation: 6876

Keep the method inside State class. Also better keep the number variable inside that class too. You can setState directly only inside the State class so that's why.

In your case, solution

class SecondRoute extends StatelessWidget {
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Lists'),
        backgroundColor: new Color(0xFF000000),
      ),
      body: DynamicChange(),
    );
  }
}

class DynamicChange extends StatefulWidget {
  @override
  StateDynamic createState() => StateDynamic();
} // Class SecondRoute

class StateDynamic extends State<DynamicChange> {
  int number = 10;

  Widget build(BuildContext context) {
    return new Scaffold(
      body: thisScreenNeeds(),
    );
  }

  Widget thisScreenNeeds() {
    return Container(
        margin: EdgeInsets.only(top: 100, left: 50),
        child: FlatButton(
          child: Text(
            number.toString(),
            textAlign: TextAlign.center,
            style: (TextStyle(
                fontWeight: FontWeight.bold,
                fontSize: 60,
                color: Colors.green)),
          ),
          onPressed: () {
            setState(() {
              number++;
            });
          },
        ));
  }
}

If you need to seperate widgets completely(as I understand first), you can send VoidCallback parameter via constructors. Like:

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  String text = 'Some text';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Text(text),
          ButtonWidget(stateSetter),
        ],
      ),
    );
  }

  void stateSetter() {
    setState(() {
      text = 'Changed text';
    });
  }
}

class ButtonWidget extends StatelessWidget {
  final VoidCallback stateSetter;

  ButtonWidget(this.stateSetter);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: this.stateSetter,
    );
  }
}

Upvotes: 12

Related Questions