從一個頁面回傳資料
在某些場景下,我們需要在回退到上一屏時同時回傳一些資料。比如,我們跳轉到新的一屏,有兩個選項讓使用者選擇,當用戶點選某個選項後會回傳到第一屏,同時在第一屏可以知道使用者選擇的訊息。
你可以使用 Navigator.pop()
來進行以下步驟:
步驟
-
建立主屏介面
-
新增按鈕,點選時跳轉到選擇介面
-
在選擇介面顯示兩個按鈕
-
當任意一個按鈕被點選,關閉選擇介面回退到主屏介面
-
在主屏介面顯示 snackbar ,展示選中的專案
1. 建立主屏介面
主屏介面顯示一個按鈕,當點選按鈕時跳轉到選擇介面。
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Returning Data Demo'),
),
// Create the SelectionButton widget in the next step.
body: const Center(
child: SelectionButton(),
),
);
}
}
2. 新增按鈕,點選時跳轉到選擇介面
接下來,我們建立 SelectionButton 按鈕,它有兩個功能:
-
點選時跳轉到選擇介面
-
等待選擇介面給它回傳結果
class SelectionButton extends StatefulWidget {
const SelectionButton({super.key});
@override
State<SelectionButton> createState() => _SelectionButtonState();
}
class _SelectionButtonState extends State<SelectionButton> {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: const Text('Pick an option, any option!'),
);
}
Future<void> _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) => const SelectionScreen()),
);
}
}
3. 在選擇介面顯示兩個按鈕
現在來建立選擇介面,它包含兩個按鈕,當任意一個按鈕被點選的時候,關閉選擇頁面回退到主屏介面,並讓主屏介面知道哪個按鈕被點選了。
這一步我們來定義 UI,在下一步完成資料的回傳。
class SelectionScreen extends StatelessWidget {
const SelectionScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () {
// Pop here with "Yep"...
},
child: const Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () {
// Pop here with "Nope"...
},
child: const Text('Nope.'),
),
)
],
),
),
);
}
}
4. 當任意一個按鈕被點選,關閉選擇介面回退到主屏介面
接下來我們來更新兩個按鈕的 onPressed()
回呼函式,使用 Navigator.pop()
回退介面並回傳資料給主屏介面。
Navigator.pop()
方法可以接受第二個引數 result
,它是可選的,如果傳遞了 result
,資料將會透過 Future
方法的回傳值傳遞。
Yep 按鈕
ElevatedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: const Text('Yep!'),
)
Nope 按鈕
ElevatedButton(
onPressed: () {
// Close the screen and return "Nope." as the result.
Navigator.pop(context, 'Nope.');
},
child: const Text('Nope.'),
)
5. 在主屏介面顯示一個 snackbar,展示選中的專案
現在,我們跳轉到選擇介面並等待回傳結果,當結果回傳時我們可以做些事情。
在本例中,我們用一個 snackbar 顯示結果,我們來更新 SelectionButton
類別中的 _navigateAndDisplaySelection()
方法。
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop.
Future<void> _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) => const SelectionScreen()),
);
// When a BuildContext is used from a StatefulWidget, the mounted property
// must be checked after an asynchronous gap.
if (!context.mounted) return;
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text('$result')));
}
互動式範例
import 'package:flutter/material.dart';
void main() {
runApp(
const MaterialApp(
title: 'Returning Data',
home: HomeScreen(),
),
);
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Returning Data Demo'),
),
body: const Center(
child: SelectionButton(),
),
);
}
}
class SelectionButton extends StatefulWidget {
const SelectionButton({super.key});
@override
State<SelectionButton> createState() => _SelectionButtonState();
}
class _SelectionButtonState extends State<SelectionButton> {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: const Text('Pick an option, any option!'),
);
}
// A method that launches the SelectionScreen and awaits the result from
// Navigator.pop.
Future<void> _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) => const SelectionScreen()),
);
// When a BuildContext is used from a StatefulWidget, the mounted property
// must be checked after an asynchronous gap.
if (!context.mounted) return;
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text('$result')));
}
}
class SelectionScreen extends StatelessWidget {
const SelectionScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Pick an option'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () {
// Close the screen and return "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: const Text('Yep!'),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () {
// Close the screen and return "Nope." as the result.
Navigator.pop(context, 'Nope.');
},
child: const Text('Nope.'),
),
)
],
),
),
);
}
}