带有 return 数据的 Flutter Back 按钮

Flutter Back button with return data

我有一个界面,其中有两个弹出按钮和 return true 或 false,如下所示:

onPressed: () => Navigator.pop(context, false)

我需要调整应用栏中的后退按钮,所以它弹出并且 return 为 false。有办法实现吗?

使用下面的代码从您的 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);
  });
}
}

完整的源代码

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,),
  );
 }
}

获取完整的 运行 如何工作的示例来自 here

首先,删除自动附加的后退按钮(参见

然后,创建您自己的后退按钮。像这样:

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

这可能对您有所帮助

第一屏

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),));
}

第二屏

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

默认 BackButton 接管 AppBar 的前导 属性,因此您需要做的就是用您的 leading 属性 覆盖自定义后退按钮,例如:

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

虽然您可以覆盖自定义行为的后退按钮,但不要这样做。

您应该处理 null 场景,而不是用自定义弹出窗口覆盖按钮。 您不想手动覆盖图标的原因有几个:

  • 图标在 IOS 和 Android 上发生变化。在 IOS 上它使用 arrow_back_ios 而 android 使用 arrow_back
  • 如果没有返回路径,图标可能会自动消失
  • 物理后退按钮仍将 return null

而是应执行以下操作:

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

实现此目的的最简单方法是:

在您的 body 中,将 WillPopScope 作为 parent 小部件 并在 onWillPop : () {} 调用

Navigator.pop(context, false);

onWillPop of WillPopScope 将在您按下 AppBar 上的后退按钮时自动触发

您可以将 data/arguments 从一个屏幕传递到另一个屏幕,

考虑这个例子:

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),
         ));
        }),
    ),
  );
 }
}

屏幕 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),
             ));
            }),
        ),
      );
     }
    }

要在屏幕之间传递数据,请将 argument/data 传递给 Navigator.pushReplacement() 中的屏幕构造函数。您可以根据需要传递任意数量的参数。

这一行

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

将转到 Screen1 并调用 Screen1 的 initState 和 build 方法,以便您可以获得更新的值。

要在导航中弹出数据并传回数据,您需要使用屏幕 1 中的 .then()。下面是示例。

屏幕 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
  ),

屏幕 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
        });
      }
   }

更简单的方法是将正文包裹在 WillPopScope 中,这样它将与顶部的 后退按钮一起工作 并且Android 底部的后退按钮

这是一个示例,其中两个后退按钮 return false:

final return = Navigator.of(context).push(MaterialPageRoute<bool>(
    builder: (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text("New Page"),
        ),
        body: WillPopScope(
          onWillPop: () async {
             Navigator.pop(context, false);
             return false;
          },
          child: newPageStuff(),
        ),
      );
    },
));

在他们建议使用的其他答案中:

leading: BackButton(...)

我发现这适用于顶部的后退按钮,而不适用于 Android 按钮。

无论如何我都包括一个例子:

final return = Navigator.of(context).push(MaterialPageRoute<bool>(
    builder: (BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          leading: BackButton(
            onPressed: () => Navigator.pop(context, false),
          ),
          title: Text("New Page"),
        ),
        body: newPageStuff(),
      );
    },
));

试试这个:

void _onBackPressed() {
  // Called when the user either presses the back arrow in the AppBar or
  // the dedicated back button.
}

@override
Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () {
      _onBackPressed();
      return Future.value(false);
    },
    child: Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.arrow_back),
          onPressed: _onBackPressed,
        ),
      ),
    ),
  );
}