Last Updated on 2021-05-12 by Clay
在我們設計一款 App 的時候,很難在同一個頁面把所有的功能做完。大多數時候,我們需要依照不同的功能,來讓使用者跳轉到不同的頁面。
比方說使用者正在主要的頁面玩遊戲,突然需要改動一些畫面的設定,那麼我們就可以設計一個按鈕,只要使用者按下按鈕,就可以跳轉到專門設定的頁面。
本篇文章主要紀錄在 Flutter 中,頁面跳轉時該如何傳遞參數、接受參數。主要分成以下三小節。
- 傳遞參數給 StatelessWidget
- 傳遞參數給 StatefulWidget
- 當頁面返回時接受回傳的參數
傳遞參數給 StatelessWidget
以下是段簡短的範例程式碼。架構相當簡單,第一頁(HomePage)只有一個輸入框跟一個按鈕,按下按鈕後,輸入框內的文字會被傳送到第二個頁面(SecondPage)。
而第二個頁面則簡單地顯示接收到的參數(第一頁輸入的文字)。
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); // MyApp class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } // HomePage class HomePage extends StatelessWidget { // TextEditingController TextEditingController _dataController = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: Center( child: Column( children: <Widget>[ TextField( autofocus: true, decoration: InputDecoration( labelText: "data:", hintText: "data will display on the second page", prefixIcon: Icon(Icons.font_download), ), obscureText: false, controller: _dataController, ), ElevatedButton( child: Text("Jump to second page"), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage( data: _dataController.text, ) ) ); }, ), ], ) ), ); } } // SecondPage class SecondPage extends StatelessWidget { SecondPage({Key? key, required this.data}) : super(key: key); final String data; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Page"), ), body: Column( children: <Widget>[ Text("the data is: $data"), ], ), ); } }
Output:
傳遞參數給 StatefulWidget
StatefulWidget 跟 StatelessWidget 的傳遞方法又有一點點微妙的不同。
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); // MyApp class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } // HomePage class HomePage extends StatelessWidget { // TextEditingController TextEditingController _dataController = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: Center( child: Column( children: <Widget>[ TextField( autofocus: true, decoration: InputDecoration( labelText: "data:", hintText: "data will display on the second page", prefixIcon: Icon(Icons.font_download), ), obscureText: false, controller: _dataController, ), ElevatedButton( child: Text("Jump to second page"), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage( data: _dataController.text, ) ) ); }, ), ], ) ), ); } } // SecondPage class SecondPage extends StatefulWidget { SecondPage({Key? key, required this.data}) : super(key: key); final String data; @override _SecondPageState createState() => _SecondPageState(); } // _SecondPageState class _SecondPageState extends State<SecondPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Page"), ), body: Column( children: <Widget>[ Text("the data is: ${widget.data}"), ], ), ); } }
Output:
其實展示效果跟前一節很像;為了證明我不是拿同個影片來放,我將 today 改成了 nice。
當頁面返回時接受回傳的參數
接受回傳的參數比較麻煩一點,我們需要另外寫異步參數,等待第二個頁面參數的回傳、並在確實取得參數後,再來更新原先的 HomePage
頁面狀態。
另外,若要回傳參數,我們也需要在 SecondPageState
的部分另外撰寫按鈕,使用 Navigator.pop(context, data);
返回我們想要的 data
參數。
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); // MyApp class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } // HomePage class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } // HomePage class _HomePageState extends State<HomePage> { // TextEditingController TextEditingController _dataController = TextEditingController(); var returnTextContent = ""; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: Center( child: Column( children: <Widget>[ TextField( autofocus: true, decoration: InputDecoration( labelText: "data:", hintText: "data will display on the second page", prefixIcon: Icon(Icons.font_download), ), obscureText: false, controller: _dataController, ), ElevatedButton( child: Text("Jump to second page"), onPressed: () { _goSecondPage(context).then((value) { setState(() { returnTextContent = value; }); }); }, ), SizedBox( height: 50.0, ), Text( returnTextContent.isNotEmpty ? returnTextContent : "No any return data", ), ], ) ), ); } // Go to the second page and receive the return value Future<String> _goSecondPage(BuildContext context) async { String returnText = await Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage( data: _dataController.text, ), ), ); print("TEST OUTPUT"); print(returnText); return returnText; } } // SecondPage class SecondPage extends StatelessWidget { SecondPage({Key? key, required this.data}) : super(key: key); final String data; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Page"), ), body: Center( child:Column( children: <Widget>[ Text("the data is: $data"), ElevatedButton( child: Text("Jump back the home page"), onPressed: () { Navigator.pop(context, data); }, ), ], ), ), ); } }
Output:
References
- https://flutter.cn/docs/cookbook/navigation/returning-data
- https://stackoverflow.com/questions/55566807/how-to-return-value-on-async-function-in-flutter