Ваша страница должна содержать Scaffold
виджет для получения функции автопрокрутки.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: MyPage()), //TODO: Add Scaffold
);
}
}
class MyPage extends StatefulWidget {
@override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final _formKey = GlobalKey<FormState>();
@override
void initState() {
super.initState();
}
@override
void dispose() {
nomController.dispose();
adresseController.dispose();
complementAdresseController.dispose();
villeController.dispose();
codePostalController.dispose();
super.dispose();
}
//controller for get value from TextFormField
TextEditingController nomController = TextEditingController();
TextEditingController adresseController = TextEditingController();
TextEditingController complementAdresseController = TextEditingController();
TextEditingController villeController = TextEditingController();
TextEditingController codePostalController = TextEditingController();
//save value in variables for send data from http request
String nom;
String adresse;
String complement;
String ville;
String codePostal;
final ScrollController _scrollController = ScrollController();
sendFormData() async {
var postUri = Uri.parse("http://51.158.67.16:8000/api/contact/");
var request = new http.MultipartRequest("POST", postUri);
request.fields['name'] = nom;
request.fields['adresse'] = adresse;
request.fields['complement'] = complement;
request.fields['city'] = ville;
request.fields['postalCode'] = codePostal;
print(nom);
print(adresse);
print(complement);
print(ville);
print(codePostal);
request.send().then((response) {
if (response.statusCode == 201) {
print("Uploaded!");
} else {
print(response.statusCode);
}
});
}
validateAndSave() async {
final form = _formKey.currentState;
if (form.validate()) {
setState(() {
nom = nomController.text;
adresse = adresseController.text;
complement = complementAdresseController.text;
ville = villeController.text;
codePostal = codePostalController.text;
});
await sendFormData();
} else {
print('form is invalid');
}
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SafeArea(
top: false,
bottom: false,
child: Container(
color: Color.fromRGBO(22, 22, 22, 1.0),
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0.0),
child: Text(
'Veuillez remplir les champs si dessous afin de nous communiquer l\'emplacement et le nom du monument ou de l\'oeuvre',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontFamily: 'Nunito',
),
),
),
Form(
key: _formKey,
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Nom de l’oeuvre",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: new TextFormField(
style: TextStyle(color: Colors.white),
controller: nomController,
onChanged: (value) {
setState(() {
nom = value;
});
},
validator: (value) {
if (value.length <= 4) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"Le nom doit contenir au minimum 4 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
],
));
}
return null;
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Nom du monument, oeuvre...',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Adresse",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: adresseController,
onChanged: (value) {
setState(() {
adresse = value;
});
},
textAlign: TextAlign.left,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(
Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0),
),
hintText: '( Optionnel ) Adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Complément d'adresse",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Container(
height: MediaQuery.of(context).size.height / 13,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: complementAdresseController,
onChanged: (value) {
setState(() {
complement = value;
});
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: '(Optionnel) Complement d’adresse',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Ville",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: villeController,
onChanged: (value) {
setState(() {
ville = value;
});
},
validator: (value) {
if (value.length <= 2) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"La ville doit contenir au minimum 2 lettres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
]));
}
return null;
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Ville',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
)),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(18, 22, 0, 4),
child: Text(
"Code Postal",
style: TextStyle(color: Colors.white, fontSize: 16),
),
)),
Align(
alignment: Alignment.centerLeft,
child: Container(
height: MediaQuery.of(context).size.height / 13,
width: MediaQuery.of(context).size.width / 1.5,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0))),
padding: EdgeInsets.fromLTRB(18, 0, 18, 0),
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: codePostalController,
onChanged: (value) {
setState(() {
codePostal = value;
});
},
validator: (value) {
if (value.length != 5) {
showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor:
Color.fromRGBO(40, 40, 40, 1.0),
titleTextStyle:
TextStyle(color: Colors.white),
title: Text(
"Le code postal doit contenir 5 chiffres"),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context),
child: Text('OK',
style: TextStyle(
fontSize: 18,
color: Colors.white)),
)
]));
}
return null;
},
keyboardType: TextInputType.number,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
hintStyle: TextStyle(
color: Color.fromRGBO(133, 133, 133, 1.0),
fontSize: 16),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10.0),
),
suffixIcon: Icon(Icons.search,
color: Color.fromRGBO(133, 133, 133, 1.0)),
hintText: 'Code postal',
fillColor: Color.fromRGBO(40, 40, 40, 1.0),
filled: true,
),
),
)),
FlatButton(
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
onPressed: () async {
await validateAndSave();
},
textColor: Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 60),
child: Container(
alignment: Alignment(0, 0),
width: MediaQuery.of(context).size.width / 2,
height: 65,
decoration: const BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10.0)),
color: Color.fromRGBO(243, 243, 243, 1.0)),
child: Text(
'ENVOYER',
style: TextStyle(
fontSize: 18,
color: Color.fromRGBO(40, 40, 40, 1.0)),
),
//padding: EdgeInsets.fromLTRB(0, 53, 0, 20),
),
),
),
],
),
)
],
),
),
),
);
}
}