我有一个带有两个按钮的界面,它们会弹出并返回true或false,就像这样:
onPressed: () => Navigator.pop(context, false)
我需要调整应用栏中的后退按钮,因此它会弹出并返回false。有没有办法做到这一点?
答案 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)
尽管您可以覆盖后退按钮以实现自定义行为,但不要这么做。
您应该处理空方案,而不是使用自定义弹出窗口覆盖按钮。 您不想手动覆盖图标的原因有几个:
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()
方法执行以下步骤:
主屏幕显示一个按钮。点击后,将启动选择屏幕。
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()),
);
}
}
现在,创建执行以下操作的SelectionButton:
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()),
);
}
}
现在,构建一个包含两个按钮的选择屏幕。当用户点击按钮时,该应用会关闭选择屏幕,并让主屏幕知道点击了哪个按钮。
此步骤定义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.'),
),
)
],
),
),
);
}
}
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!'),
);
现在,您将启动一个选择屏幕并等待结果,您将需要对返回的信息进行处理。
在这种情况下,使用_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.'),
),
)
],
),
),
);
}
}
答案 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,
),
),
),
);
}