我有这个问题,我有一个两步表格。我加载了一个本地 JSON 文件以启动状态,以便在下拉小部件的第二步中使用。但是,当我单击继续按钮并切换到第二种形式时,变量更改为 null 导致出现错误“方法 'map' 在 null 上被调用”。我尝试在 continueButton 小部件的 onPressed 函数中加载数据,并在创建第二种形式的小部件之一时尝试再次加载。但是我总是收到这个错误,即在 null 上调用了 map 函数。请帮忙 !!!
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
import 'package:ofepaw/services/auth.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
class RegisterPage extends StatefulWidget {
final Function toggleView;
RegisterPage({this.toggleView});
@override
State createState() => RegisterPageState();
}
class RegisterPageState extends State<RegisterPage> {
final AuthService _auth = AuthService();
// store the step we are in
int step = 1;
// Text Field
String emailOrPhone = "";
String pass = "";
String verifyPass = "";
String firstName = "";
String lastName = "";
String department = "";
String arrondissement = "";
String commune = "";
// variable for errors
String error = "";
// array containing the forms
var form1;
var form2;
// Controllers for the Textfields
final _emailOrPhoneController = TextEditingController();
final _passwordController = TextEditingController();
final _verifyPassController = TextEditingController();
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
//final _departmentController = TextEditingController();
//load the geographic division of Haiti json file
var division;
// get the locations data
Future<void> loadDivision() async {
String jsonString = await rootBundle
.loadString('assets/haiti_administrative_district.json');
Map<String, dynamic> map = json.decode(jsonString);
List<dynamic> data = map["departments"];
setState(() {
division = data;
});
}
// function to register user in ofepaw database
Future registerUser(
String id, String fname, String lname, String department) async {
final String url = "url go here";
final response = await http.post(url, body: {
"id": id,
"fname": fname,
"lname": lname,
"department": department
});
if (response.statusCode == 201) {
print("This is the response from the server");
print(response.body);
print("Response passed");
} else {
print("Error occured");
}
print(" The response is : ");
print(response.body.toString());
}
//functions for switching forms
getForm(int form) {
if (form == 1) {
return form1;
} else if (form == 2) {
return form2;
}
}
@override
void initState() {
super.initState();
loadDivision();
print(division);
form1 = <Widget>[
firstForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
InkWell(
onTap: () {
widget.toggleView();
},
child: Text("Have an account? Login"))
];
form2 = <Widget>[
secondForm(),
InkWell(
//back button
onTap: () => setState(() => step = 1),
child: Text("Back"))
];
}
// dispose all controllers
// dispose of all TextEditingControllers
@override
void dispose() {
_emailOrPhoneController.dispose();
_passwordController.dispose();
_verifyPassController.dispose();
_firstNameController.dispose();
_lastNameController.dispose();
//_departmentController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Material(
child: Expanded(
child: Stack(
children: <Widget>[
// banner with picture
Positioned(
child: banner(),
),
// Login Elements Container
Positioned(
child: Container(
margin: EdgeInsets.only(top: 300.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.only(
topRight: Radius.circular(50),
topLeft: Radius.circular(50))),
child: Center(
child: Column(
children: getForm(step),
),
),
),
)
],
),
),
);
}
Widget banner() {
return Container(
height: 350,
decoration: BoxDecoration(color: Colors.white),
child: Center(
child: Image.network(
"https://image.freepik.com/free-vector/man-using-his-phone-instead-working_23-2148501890.jpg"),
),
);
}
Widget emailField() {
return TextFormField(
controller: _emailOrPhoneController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "Email or Phone Number",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => emailOrPhone = val);
},
);
}
Widget firstNameField() {
return TextFormField(
controller: _firstNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
Widget lastNameField() {
return TextFormField(
controller: _lastNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "Last Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => lastName = val);
},
);
}
Widget departmentField() {
return DropdownButtonFormField(
items: division.map<DropdownMenuItem<String>>((value) {
return DropdownMenuItem<String>(
value: value["name"],
child: Text(value["name"]),
);
}).toList(),
hint: Text("Choose the department"),
onChanged: (value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
);
}
Widget arrondissementField() {
return DropdownButtonFormField(
items: [
DropdownMenuItem(
child: Text("Delmas"),
value: 1,
),
DropdownMenuItem(
child: Text("Petion-Ville"),
value: 2,
)
],
hint: Text("Choose the department"),
onChanged: (int value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)));
}
Widget communeField() {
return DropdownButtonFormField(
items: [
DropdownMenuItem(
child: Text("Delmas"),
value: 1,
),
DropdownMenuItem(
child: Text("Petion-Ville"),
value: 2,
)
],
hint: Text("Choose the department"),
onChanged: (int value) {
setState(() {});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)));
}
Widget passwordField() {
return TextFormField(
controller: _passwordController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 5, left: 20, right: 20),
border: InputBorder.none,
hintText: "Password",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => pass = val);
});
}
Widget verifyPasswordField() {
return TextFormField(
controller: _verifyPassController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 5, left: 20, right: 20),
border: InputBorder.none,
hintText: "Reenter Password",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => verifyPass = val);
});
}
Widget socialMediaButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SignInButton(Buttons.Facebook,
mini: true, onPressed: () => print("Facebook Sign in ...")),
SignInButton(Buttons.Google,
//mini: true,
onPressed: () => print("Google Sign in ..."))
],
);
}
Widget continueButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("continue"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () {
print(division);
setState(() {
step = 2;
});
},
));
}
Widget signUpButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("Sign Up"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () async {
dynamic result =
await _auth.registerWithEmailAndPassword(emailOrPhone, pass);
if (result == null) {
setState(() => error = "Email or Password incorrect");
} else {
// Register user ID in the server database
registerUser(result.user.uid, firstName, lastName, department);
}
},
));
}
Widget emailPassField() {
return Container(
// Form input field
margin: EdgeInsets.only(top: 40.0),
width: 320.0,
height: 180.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 0.2,
blurRadius: 5,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.circular(20)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
emailField(),
Divider(),
passwordField(),
Divider(),
verifyPasswordField()
],
),
);
}
Widget personalInfoField() {
return Container(
// Form input field
margin: EdgeInsets.only(top: 40.0),
width: 320.0,
height: 310.0,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 0.2,
blurRadius: 5,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.circular(20)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
firstNameField(),
Divider(),
lastNameField(),
Divider(),
departmentField(),
Divider(),
arrondissementField(),
Divider(),
communeField()
],
),
);
}
Widget firstForm() {
return Column(
children: <Widget>[
emailPassField(),
SizedBox(
height: 50,
),
continueButton(),
SizedBox(
height: 50,
),
],
);
}
Widget secondForm() {
return Column(
children: <Widget>[
personalInfoField(),
SizedBox(
height: 40,
),
signUpButton(),
SizedBox(
height: 40,
),
],
);
}
}