Flutter Back button with return data

ぃ、小莉子 提交于 2019-11-28 01:00:12

This may help and work for you

1st screen

void goToSecondScreen()async {
 var result = await Navigator.push(_context, new MaterialPageRoute(
 builder: (BuildContext context) => new SecondScreen(context),
 fullscreenDialog: true,)
);

Scaffold.of(_context).showSnackBar(SnackBar(content: Text("$result"),duration: Duration(seconds: 3),));

}

2nd screen

Navigator.pop(context, "Hello world");

The default BackButton takes over the leading property of your AppBar so all you need to do is to override the leading property with your custom back button, for example:

leading: IconButton(icon:Icon(Icons.chevron_left),onPressed:() => Navigator.pop(context, false),),)

To pop the data and pass data back on navigation, you need to use .then() from screen 1. Below is the example.

Screen 2:

class DetailsClassWhichYouWantToPop {
  final String date;
  final String amount;
  DetailsClassWhichYouWantToPop(this.date, this.amount);
}

void getDataAndPop() {
      DetailsClassWhichYouWantToPop detailsClass = new DetailsClassWhichYouWantToPop(dateController.text, amountController.text);
      Navigator.pop(context, detailsClass); //pop happens here
  }

new RaisedButton(
    child: new Text("Edit"),
    color:  UIData.col_button_orange,
    textColor: Colors.white,
    onPressed: getDataAndPop, //calling pop here
  ),

Screen 1:

    class Screen1 extends StatefulWidget {
          //var objectFromEditBill;
          DetailsClassWhichYouWantToPop detailsClass;

          MyBills({Key key, this.detailsClass}) : super(key: key);

          @override
          Screen1State createState() => new Screen1State();
        }

        class Screen1State extends State<Screen1> with TickerProviderStateMixin {


        void getDataFromEdit(DetailsClassWhichYouWantToPop detailClass) {
        print("natureOfExpense Value:::::: " + detailClass.date);
        print("receiptNumber value::::::: " + detailClass.amount);
      }

      void getDataFromEdit(DetailsClassWhichYouWantToPop detailClass) {
        print("natureOfExpense Value:::::: " + detailClass.natureOfExpense);
        print("receiptNumber value::::::: " + detailClass.receiptNumber);
      }

      void pushFilePath(File file) async {
        await Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => Screen2(fileObj: file),
          ),
        ).then((val){
          getDataFromScreen2(val); //you get details from screen2 here
        });
      }
   }

While you can override the back button for custom behaviors, don't.

Instead of overriding the button with a custom pop, you should handle the null scenario. There are a few reasons why you don't want to manually override the icon:

  • The icon change on IOS and Android. On IOS it uses arrow_back_ios while android uses arrow_back
  • The icon may automatically disappear if there's no route to go back
  • Physical back button will still return null.

Instead should do the following:

var result = await Navigator.pushNamed<bool>(context, "/");
if (result == null) {
  result = false;
}

First, Remove the automatically appended back button (see this answer)

Then, create your own back button. like this:

IconButton(
    onPressed: () => Navigator.pop(context, false),
    icon: Icon(Icons.arrow_back),
    )

Use the below code to get result from your activity.

Future _startActivity() async {

Map results = await Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context){
  return new StartActivityForResult();
}));

if (results != null && results.containsKey('item')) {
  setState(() {
    stringFromActivity = results['item'];
    print(stringFromActivity);
  });
}
}

Complete Source Code

import 'package:flutter/material.dart';
import 'activity_for_result.dart';
import 'dart:async';
void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
 return new MaterialApp(
   title: 'Flutter Demo',
   theme: new ThemeData(
    primarySwatch: Colors.blue,
  ),
     home: new MyHomePage(title: 'Start Activity For Result'),
  );
 }
}

class MyHomePage extends StatefulWidget {
 MyHomePage({Key key, this.title}) : super(key: key);
 final String title;

 @override
 _MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
 String stringFromActivity = 'Start Activity To Change Me \n😀😀😀';
 @override
 Widget build(BuildContext context) {
 return new Scaffold(
  appBar: new AppBar(
    title: new Text(widget.title),
  ),
  body: new Center(
    child: new Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        new Text(
          stringFromActivity, style: new TextStyle(fontSize: 20.0), textAlign: TextAlign.center,
        ),
        new Container(height: 20.0,),
        new RaisedButton(child: new Text('Start Activity'),
          onPressed: () => _startActivity(),)
      ],
    ),
  ),
);
}

Future _startActivity() async {

Map results = await Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context){
  return new StartActivityForResult();
}));

if (results != null && results.containsKey('item')) {
  setState(() {
    stringFromActivity = results['item'];
    print(stringFromActivity);
  });
 }
 }
}

import 'package:flutter/material.dart';

class StartActivityForResult extends StatelessWidget{

 List<String>list = ['😀😀😀','😆😆😆','😍😍😍','😋😋😋','😡😡😡','👿👿👿','🎃','🤖','👾',];

 @override
 Widget build(BuildContext context) {
// TODO: implement build

  return new Scaffold(
    appBar: new AppBar(
    title: new Text('Selecte Smily'),
  ),
  body: new ListView.builder(itemBuilder: (context, i){
    return new ListTile(title: new Text(list[i]),
      onTap: (){
        Navigator.of(context).pop({'item': list[i]});
      },
    );
  }, itemCount: list.length,),
  );
 }
}

get complete running example of how to work this from here

The simplest way to achieve this is to :

In your body take a WillPopScope as the parent widget And on its onPop : () {} call

Navigator.pop(context, false);

onPop of WillPopScope will be triggered automatically when you’ll press the back button on your appbar

You can pass data/arguments from one screen to other,

consider this example:

screen1.dart:

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

class Screen1 extends StatelessWidget {
  Screen1(this.indx);

  final int indx;

  @override
  Widget build(BuildContext context) {
    return new S1(indx: indx,);
  }
}

class S1 extends StatefulWidget {
  S1({Key key, this.indx}) : super(key: key);

  final int indx;

  @override
  S1State createState() => new S1State(indx);
}

class S1State extends State<VD> {

    int indx = 5;

  @override
  Widget build(BuildContext context) {
   return new Scaffold(
      appBar: new AppBar(
        leading: new IconButton(icon: const Icon(Icons.iconName), onPressed: () {
          Navigator.pushReplacement(context, new MaterialPageRoute(
            builder: (BuildContext context) => new Screen2(indx),
         ));
        }),
    ),
  );
 }
}

Screen 2:

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

class Screen2 extends StatelessWidget {
 Screen2(this.indx);

 final int indx;

 @override
 Widget build(BuildContext context) {
       return new S2(indx: indx,);
    }
 }

 class S2 extends StatefulWidget {
  S2({Key key, this.indx}) : super(key: key);

  final int indx;

  @override
  S2State createState() => new S2State(indx);
  }

 class S2State extends State<VD> {

 int indx = 1;

  @override
      Widget build(BuildContext context) {
       return new Scaffold(
          appBar: new AppBar(
            leading: new IconButton(icon: const Icon(Icons.Icons.arrow_back), onPressed: () {
              Navigator.pushReplacement(context, new MaterialPageRoute(
                builder: (BuildContext context) => new Screen1(indx),
             ));
            }),
        ),
      );
     }
    }

To pass data between Screens, pass the argument/data to the Screens constructor in Navigator.pushReplacement().You can pass as many argument as you want.

This line

Navigator.pushReplacement(context, new MaterialPageRoute(
                    builder: (BuildContext context) => new Screen1(indx),
                 ));

will go to Screen1 and call initState and build method of Screen1 so that you can get updated values.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!