带有返回数据的Flutter Back按钮

时间:2018-08-20 09:34:49

标签: flutter flutter-layout

我有一个带有两个按钮的界面,它们会弹出并返回true或false,就像这样:

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

我需要调整应用栏中的后退按钮,因此它会弹出并返回false。有没有办法做到这一点?

11 个答案:

答案 0 :(得分:31)

更简单的方法是将主体包裹在 WillPopScope 中,这样可以与顶部的 Back Button 和Android上的 Android Back Button一起使用底部

在此示例中,两个后退按钮均返回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(),
        ),
      );
    },
));

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

领先: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(),
      );
    },
));

答案 1 :(得分:8)

默认的BackButton继承了AppBar的首页属性,因此您要做的就是使用自定义后退按钮覆盖leading属性,例如:

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

答案 2 :(得分:3)

这可能对您有所帮助

第一个屏幕

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");

答案 3 :(得分:3)

要弹出数据并将数据传递回导航,您需要使用屏幕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
        });
      }
   }

答案 4 :(得分:0)

使用以下代码从您的活动中获取结果。

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

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

尽管您可以覆盖后退按钮以实现自定义行为,但不要这么做。

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

  • 在iOS和Android上图标更改。在IOS上,它使用arrow_back_ios,而android使用arrow_back
  • 如果没有返回路线,该图标可能会自动消失
  • 物理后退按钮仍将返回null

相反,应执行以下操作:

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

答案 7 :(得分:0)

最简单的方法是:

在您的身体中,将WillPopScope作为父窗口小部件 并在其onPop上:(){}调用

Navigator.pop(context, false);
按下应用栏上的后退按钮

时,WillPopScope的

onPop将自动触发

答案 8 :(得分:0)

您可以将数据/参数从一个屏幕传递到另一屏幕,

考虑以下示例:

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

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

此行

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

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

答案 9 :(得分:0)

从屏幕返回数据

您可以使用Navigator.pop()方法执行以下步骤:

  1. 定义主屏幕

主屏幕显示一个按钮。点击后,将启动选择屏幕。

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Returning Data Demo'),
      ),
      // Create the SelectionButton widget in the next step.
      body: Center(child: SelectionButton()),
    );
  }
}
  1. 添加一个启动选择屏幕的按钮

现在,创建执行以下操作的SelectionButton:

  1. 在点击SelectionScreen时启动它。
  2. 等待SelectionScreen返回结果。
class SelectionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the
  // result from Navigator.pop.
  _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that completes after calling
    // Navigator.pop on the Selection Screen.
    final result = await Navigator.push(
      context,
      // Create the SelectionScreen in the next step.
      MaterialPageRoute(builder: (context) => SelectionScreen()),
    );
  }
}
  1. 通过两个按钮显示选择屏幕

现在,构建一个包含两个按钮的选择屏幕。当用户点击按钮时,该应用会关闭选择屏幕,并让主屏幕知道点击了哪个按钮。

此步骤定义UI。下一步添加代码以返回数据。

class SelectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Pick an option'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Pop here with "Yep"...
                },
                child: Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Pop here with "Nope"
                },
                child: Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}
  1. When a button is tapped, close the selection screen

现在,更新两个按钮的onPressed()回调。要将数据返回到第一个屏幕,请使用Navigator.pop()方法,该方法接受一个称为result的可选第二个参数。任何结果都将通过SelectionButton返回到Future。

RaisedButton(
  onPressed: () {
    // The Yep button returns "Yep!" as the result.
    Navigator.pop(context, 'Yep!');
  },
  child: Text('Yep!'),
);
  1. 在主屏幕上显示带有选择项的小吃店

现在,您将启动一个选择屏幕并等待结果,您将需要对返回的信息进行处理。

在这种情况下,使用_navigateAndDisplaySelection()中的SelectionButton方法显示一个显示结果的小吃店:

_navigateAndDisplaySelection(BuildContext context) async {
  final result = await Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SelectionScreen()),
  );

  // After the Selection Screen returns a result, hide any previous snackbars
  // and show the new result.
  Scaffold.of(context)
    ..removeCurrentSnackBar()
    ..showSnackBar(SnackBar(content: Text("$result")));
}

互动示例

class SelectionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the result from
  // Navigator.pop.
  _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that completes after calling
    // Navigator.pop on the Selection Screen.
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SelectionScreen()),
    );

    // After the Selection Screen returns a result, hide any previous snackbars
    // and show the new result.
    Scaffold.of(context)
      ..removeCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text("$result")));
  }
}

class SelectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Pick an option'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Close the screen and return "Yep!" as the result.
                  Navigator.pop(context, 'Yep!');
                },
                child: Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Close the screen and return "Nope!" as the result.
                  Navigator.pop(context, 'Nope.');
                },
                child: Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

enter image description here

Doc:Return data from a screen

答案 10 :(得分:0)

尝试一下:

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