android - Pass data from one page to another in Flutter
问题描述
I know there are a ton of questions like these but I'm brand new to Flutter and I haven't found a post that suits my needs or maybe I'm just thinking about it wrong.
I basically have settings.dart
and home.dart
. Right now, what I'd like to do is based on the checkbox value for either metres _isMetresChecked
or feet _isFeetChecked
, change the unit on the home screen but don't immediately switch to the home screen, allow the user to continue configuring settings (there are more to add in eventually) and when they go back to the homescreen, it updates. I tried to use the class SettingsData
as a way to merge all the configurations and then pass it via Navigator
but despite the fact that I was unsuccessful, it wouldn't have let me allow the user to stay on the 'Settings' page.
So how can I pass data between views, without switching views?
home.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'applicationbar.dart';
import 'navigationdrawer.dart';
import 'bluetooth.dart';
class LuggageFollowerMain extends StatefulWidget {
@override
_LuggageFollowerMainState createState() => _LuggageFollowerMainState();
}
class _LuggageFollowerMainState extends State<LuggageFollowerMain> {
String _string = '0m'; //so if _isFeetChecked is true in settings.dart this is '0ft'
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: ApplicationBar(title: 'Luggage Follower'),
drawer: NavigationDrawer(),
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
child: Text('Luggage Status', style: Theme.of(context).textTheme.body2),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
child: Text('Paired', style: Theme.of(context).textTheme.body1),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 0),
child: Divider(height: 3.0, color: Colors.pinkAccent, indent: 150, endIndent: 150),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
child: Text('Distance to Luggage', style: Theme.of(context).textTheme.body2),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
child: Text(_string, style: Theme.of(context).textTheme.body1), //dynamic text here
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
child: LuggageFollow(),
),
],
),
);
}
}
settings.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:audioplayers/audio_cache.dart';
import 'applicationbar.dart';
import 'navigationdrawer.dart';
class SettingsData {
bool feet;
bool metres;
SettingsData({this.feet, this.metres});
}
class Settings extends StatefulWidget {
@override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
static bool _isFeetChecked = false;
static bool _isMetersChecked = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ApplicationBar(title: 'Settings'),
drawer: NavigationDrawer(),
body: Column(
//crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 20),
child: Text('Distance Units')
),
Divider(
height: 3.0,
color: Colors.pink,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
child: CheckboxListTile(
title: Text('Distance in feet', style: Theme.of(context).textTheme.body1),
value: _isFeetChecked,
onChanged: (bool value) {
setState(() {
_isFeetChecked = value; _isMetersChecked = !value;});
},
checkColor: Colors.white,
activeColor: Colors.pink,
subtitle: Text('1 foot ~ 0.3 metres',style: Theme.of(context).textTheme.display2),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
child: CheckboxListTile(
title: Text('Distance in metres', style: Theme.of(context).textTheme.body1),
value: _isMetersChecked,
onChanged: (bool value) {
setState(() { _isMetersChecked = value; _isFeetChecked = !value;updateData();});
},
checkColor: Colors.white,
activeColor: Colors.pink,
subtitle: Text('1 metre ~ 3 feet',style: Theme.of(context).textTheme.display2),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 30.0,horizontal: 20),
child: Text('Notifications')
),
Divider(
height: 3.0,
color: Colors.pink,
),
),
),
],
),
);
}
}
解决方案
So first of all you only need 1 bool for your measurements. It's either feet or meters. So that simplifies things a bit. Here is a example using a callback function to set the state change in the parent widget. This is just one way of many this can be done and there may be other ways you may like better.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LuggageFollowerMain(),
);
}
}
class Settings extends StatefulWidget {
//Static references to our parent widget varibles
final bool isM;
final changeMeeters;
Settings(bool isM, changeMeeters(bool meeters)):
this.isM = isM,
this.changeMeeters = changeMeeters
;
@override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
@override
void initState() {
super.initState();
//set our varible state to be that of the parent screen
//isMeeters is a local var to Settings and is changeable.
//isM is a static and can't be changed. isM was passed in
//from our home screen. We need a changeable var or the
//checkboxes won't update correctly. Thats why we need
//isMeeters (lol bad spelling). When the settings screen
//first loads we use initState to take the value of
//isM(from our home screen) and copy it into isMeeters
//as it's initial value before it is built and shown
//to the user for the first time.
isMeeters = widget.isM;
}
//our varible to use for our check boxes
var isMeeters;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20),
child: Text('Distance Units')),
Divider(
height: 3.0,
color: Colors.pink,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 0),
child: CheckboxListTile(
title: Text('Distance in feet',
style: Theme.of(context).textTheme.body1),
//use the local var change when tapped
value: isMeeters,
onChanged: (bool value) {
setState(() {
isMeeters = true;
});
//call back to the parent widget so it can be updated
widget.changeMeeters(true);
},
checkColor: Colors.white,
activeColor: Colors.pink,
subtitle: Text('1 foot ~ 0.3 metres',
style: Theme.of(context).textTheme.display2),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 0),
child: CheckboxListTile(
title: Text('Distance in metres',
style: Theme.of(context).textTheme.body1),
//use the local var change when tapped. Use ! to invert the bool. This way only one is needed.
value: !isMeeters,
onChanged: (bool value) {
setState(() {
isMeeters = false;
});
//call back to the parent widget so it can be updated
widget.changeMeeters(false);
},
checkColor: Colors.white,
activeColor: Colors.pink,
subtitle: Text('1 metre ~ 3 feet',
style: Theme.of(context).textTheme.display2),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 20),
child: Text('Notifications')),
Divider(
height: 3.0,
color: Colors.pink,
),
],
),
);
}
}
class LuggageFollowerMain extends StatefulWidget {
@override
_LuggageFollowerMainState createState() => _LuggageFollowerMainState();
}
class _LuggageFollowerMainState extends State<LuggageFollowerMain> {
//store the distance as a number not a string
double distance = 0.0;
//store the measurement type setting
bool isMeeters = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Settings(isMeeters, (newMeeters){
//when we get our callback from settings we set the change to the home screen var here
setState(() {
isMeeters = newMeeters;
});
})),
);
},
),
backgroundColor: Colors.grey[900],
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
child: Text('Luggage Status',
style: Theme.of(context).textTheme.body2),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
child: Text('Paired', style: Theme.of(context).textTheme.body1),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 0),
child: Divider(
height: 3.0,
color: Colors.pinkAccent,
indent: 150,
endIndent: 150),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
child: Text('Distance to Luggage',
style: Theme.of(context).textTheme.body2),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
//use the new number var and change it's suffix m or f depending on what our setting is.
child: Text(distance.toString() + (isMeeters ? "m" : "f"),
style: Theme.of(context).textTheme.body1), //dynamic text here
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
),
],
),
);
}
}
推荐阅读
- c# - 正则表达式 C#:清理错误的 Json 字符串
- javascript - 在同一个 JS 脚本中读取自己的 JS 域 URL 的 cookie
- java - Android Service 需要在后台运行,直到应用程序被杀死
- java - 是什么导致我的抽象类中的错误?
- php - php >! 运营商不合法但有效
- node.js - fs.readdirSync 包含子目录
- java - 无法在 Android 中检索 Firebase 数据库
- php - 获取树枝文件内容并传递变量
- microsoft-dynamics - Microsoft Dynamics NAV:错误消息日志
- php - Yii2调用控制台控制器/后端控制器中的动作