Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Always execute a function when the page appears

Tags:

flutter

dart

How could I make the name() function run whenever the Page1 page appeared?

In the code below before going to Page2 I execute the dispose() Already inside Page2 if I click the back button or the physical button of Android the function name() is not executed, but if I click the 'go to Page1' button the function name() is executed.

Could you help me to always execute the name() function when Page1 appears?

enter image description here

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {  
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
      routes: <String, WidgetBuilder> {
        '/page2': (BuildContext context) => new Page2(),
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String nameScreen;

  String name() {
    return 'foo1';
  }

  @override
  void initState() {
    super.initState();
    this.nameScreen = name();

  }

  @override
  void dispose() {
    this.nameScreen = '';
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Page 1'),
        backgroundColor: new Color(0xFF26C6DA),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new RaisedButton(
              child: const Text('go to Page2'),
              onPressed: () async {
                dispose();
                bool isLoggedIn = await Navigator.of(context).pushNamed('/page2');
                if (isLoggedIn) {
                  setState((){
                    this.nameScreen = name();
                  });
                }
              },
            ),            
            new Text(
              '$nameScreen',              
            ),
          ],
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return new Scaffold( 
      appBar: new AppBar(
        title: new Text('Page 2'),
        backgroundColor: new Color(0xFFE57373)
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new RaisedButton(
              child: const Text('go back to Page1'),
              onPressed: () {
                Navigator.pop(context, true);
              }
            ),
          ],
        ),
      ),
    );
  }
}
like image 681
rafaelcb21 Avatar asked Oct 31 '17 02:10

rafaelcb21


People also ask

How do you call a function automatically in Flutter?

You should make the call of your function in initState rather then in widget tree as everytime the widget is rebuild, it will call the function to execute again and again(leading to more reads).

What is the use of addPostFrameCallback?

addPostFrameCallback method Null safetyIf a frame is in progress and post-frame callbacks haven't been executed yet, then the registered callback is still executed during the frame. Otherwise, the registered callback is executed during the next frame.


4 Answers

There is no need to call dispose at all when you are willing to pop and change State later, since dispose will remove the current object from the tree, which does not translate to the logic you are trying to develop.

You can indeed override the BackButton and pass the same call of Navigator.pop(context, result) to it. Check the following example I have tweaked your code a little bit to show you the difference between each State of your nameScreen field. I hope this helps you.

enter image description here

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String nameScreen = "";

  String name() {
    return 'foo1';
  }

  @override
  void initState() {
    super.initState();
    this.nameScreen = "From initState";

  }

@override
void dipose(){
    super.dispose();
}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page 1'),
        backgroundColor: Color(0xFF26C6DA),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              child: const Text('go to Page2'),
              onPressed: () async {
                //dispose(); ///No need for dispose
                String result = await Navigator.of(context).pushNamed('/page2');

                  setState((){
                    this.nameScreen = result;
                  });

              },
            ),
            Text(
              '$nameScreen',
            ),
          ],
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: ()async{
            Navigator.pop(context,"From BackButton");
          }),
          title: const Text('Page 2'),
          backgroundColor: Color(0xFFE57373)
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
                child: const Text('go back to Page1'),
                onPressed: () {
                  Navigator.pop(context, "From RaisedButton");
                }
            ),
          ],
        ),
      ),
    );
  }
like image 160
Shady Aziza Avatar answered Oct 21 '22 12:10

Shady Aziza


One way of doing this is to use the .whenComplete() method on the Navigator widget.

Suppose you are going to the second page from the first page. Here you have to pass the functionThatSetsTheState as a pointer to the navigation part of your code.

The function looks like this and should be in a Stateful Widget.

void functionThatSetsTheState(){
 setState(() {});
}

Your navigation code for OnPressed, OnTap, OnLongPress, etc.

Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => SecondPage())).whenComplete(() => {functionThatSetsTheState()});
like image 36
Shashwat Priyadarshy Avatar answered Oct 21 '22 12:10

Shashwat Priyadarshy


You can use RouteObserves if you want to execute some function whenever your page appears, you will have to implement RouteAware on the page where you want to run execute the function whenever the screens appears, you're gonna have to do something like this on ur Page1

final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>(); // add this on your main class
void main() {
  runApp(MaterialApp(
    home: Container(),
    navigatorObservers: [routeObserver], // add observer here;
  ));
} 





// your page where func should run whenever this page appears
class MyHomePage extends StatefulWidget with RouteAware {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String nameScreen = "";

  String name() {
    return 'foo1';
  }

  @override
  void initState() {
    super.initState();
    this.nameScreen = "From initState";

  }

 @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context));
  }

  @override
  void dispose() {
    routeObserver.unsubscribe(this);
    super.dispose();
  }

// implementing RouteAware method
void didPush() {
// Route was pushed onto navigator and is now topmost route.
    name(); // your func goes here
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Page 1'),
        backgroundColor: Color(0xFF26C6DA),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              child: const Text('go to Page2'),
              onPressed: () async {
                //dispose(); ///No need for dispose
                String result = await Navigator.of(context).pushNamed('/page2');

                  setState((){
                    this.nameScreen = result;
                  });

              },
            ),
            Text(
              '$nameScreen',
            ),
          ],
        ),
      ),
    );
  }
}

you can head over to this link for more explanation https://api.flutter.dev/flutter/widgets/RouteObserver-class.html

like image 27
Anas Iqbal Avatar answered Oct 21 '22 13:10

Anas Iqbal


You can override the back button on the second screen. And instead of system closing, do

WillPopScope(
    onWillPop: () {
       print('back pressed');
       Navigator.pop(context, "From BackButton");
       return true;
      },
    child: Scaffold(...)
like image 2
Misha Babec Avatar answered Oct 21 '22 12:10

Misha Babec