Related
I have a statefull layout with a listview.builder inside the builder I have a couple of expansionTile widgets
How do I show the entire list on the screen and add some textform widget below the list?
I have added a Expanded widget around the list to allow for more widgets below it but the list gets cut at a certain point where I want to show the entire list and then the text widgets after
class ContactUsScreen extends StatefulWidget {
const ContactUsScreen({Key? key}) : super(key: key);
static const String contactRouteName = "/contactScreen";
#override
State<ContactUsScreen> createState() => _ContactUsScreenState();
}
class _ContactUsScreenState extends State<ContactUsScreen> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("Contact Us"),
centerTitle: true,
),
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: true,
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: salesList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 5,
child: ExpansionTile(
key: PageStorageKey<ContactPeople>(salesList[index]),
controlAffinity: ListTileControlAffinity.leading,
childrenPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
expandedCrossAxisAlignment: CrossAxisAlignment.end,
maintainState: true,
title: Text(
salesList[index].regionDescription,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
children: //[Text("Test")],
salesList[index].people!.map(
(peopleRecord) {
return ExpansionTile(
expandedCrossAxisAlignment: CrossAxisAlignment.start,
key: PageStorageKey<ContactUsScreen>(peopleRecord),
title: Align(
alignment: Alignment.topLeft,
child: Row(
children: [
ClipOval(
child: Image.asset(
"assets/images/people/${peopleRecord.avatarImage}",
fit: BoxFit.cover,
width: 60,
height: 60,
),
),
SizedBox(
width: 10,
),
Text(
peopleRecord.name,
style: const TextStyle(fontSize: 15),
),
],
),
),
children: [
Text(
peopleRecord.title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(peopleRecord.cellPhoneNumber),
Text(
peopleRecord.emailAddress,
),
const SizedBox(
height: 5,
),
],
);
},
).toList(),
),
),
);
}),
),
SizedBox(height: 15,),
Text("Contact us directly",
style: TextStyle(fontWeight: FontWeight.w700,
fontSize: 20,
color: Colors.black),),
Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextFormField(controller: fullNameController,
keyboardType: TextInputType.text,
decoration: InputDecoration(labelText: "Full Name",
hintText: "Full Name",
),
validator: (inputFieldFullName)
{
if(inputFieldFullName!.isEmpty)
{
return "Please enter your Full Name";
}
else
{
return null;
}
},
),
TextFormField(controller: contactNumberController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: "Contact Number",
hintText: "Contact Number",
),
validator: (inputFieldContactNumber)
{
if(inputFieldContactNumber!.isEmpty)
{
return "Please enter your contact number";
}
else
{
return null;
}
},
),
SizedBox(height: 5,),
ElevatedButton(
onPressed: () {
if(formKey.currentState!.validate())
{
//Send the email
}
else
{
const SnackBar snackBar = SnackBar(duration: Duration(seconds: 2), content: Text("Please correct the errors"));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
},
child: Text("Submit"),
),
SizedBox(height: 20,),
],
),
),
),
//getContactForm(context, formKey),
],
),
)
],
)
),
);
}
}
The end result should be that we display the entire list of parent expansion tile, and then only after the textform fields
Regards
You have to use this structure:
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ** first listview **
},
childCount: top.length,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ** second listview **
},
childCount: bottom.length,
),
),
],
),
I am making an app in Flutter. Now I have put validator that to validate the email. But I want that if there is an google gmail account or any other valid email (actually has the user) then only the user should create account in app.
For example - Currently if I enter xyz#gmail.com then also the account is created on my app though this email doesn't exists as google account.
So my question is, Is there any way that app should validate first (If the email is valid account on gmail, outlook or any other but should be valid) and then account will create otherwise it should give error that Enter valid email???
I am using Firebase for Authentication.
My Code is below LoginPage.dart
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
String _email, _password, error = '';
bool _obscureText = true;
final Auth _auth = Auth();
_toggle(){
setState(() {
_obscureText = !_obscureText;
});
}
_submit() async {
if(_formKey.currentState.validate()){
_formKey.currentState.save();
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('email', _email);
dynamic result = await _auth.login(_email, _password);
if(result == null){
setState(() => error = 'There is no user record found. Please create account first!!!');
} else {
Navigator.pushNamed(context, HomePage.id);
}
print(_email);
print(_password);
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Login',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 10.0),
child: Padding(
padding: EdgeInsets.only(left: 5, right: 5, top: 5),
child: TextFormField(
decoration: InputDecoration(
labelText: 'Email',
border: InputBorder.none,
filled: true,
fillColor: Colors.white60,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue,width: 2.0),
borderRadius: BorderRadius.circular(10.0)
),
/*enabledBorder: UnderlineInputBorder(
borderRadius: BorderRadius.circular(10.0)
)*/
),
validator: (input) => !input.contains('#')
? 'Please enter valid email'
: null,
onSaved: (input) => _email = input,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 10.0),
child: Stack(
alignment: const Alignment(0, 0),
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: InputBorder.none,
filled: true,
fillColor: Colors.white60,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue,width: 2.0),
borderRadius: BorderRadius.circular(10.0)
),
),
validator: (input) => input.length < 6
? 'Must be at least 6 characters'
: null,
onSaved: (input) => _password = input,
obscureText: _obscureText,
),
Positioned(
right: 15,
child: Container(
height: 30,
child: ElevatedButton(
onPressed: (){
_toggle();
},
child: Text(
_obscureText ? 'Show' : 'Hide'
),
),
),
),
],
),
),
verticalSpaceMedium,
Container(
width: 200.0,
child: TextButton(
onPressed: _submit,
style: TextButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blue,
elevation: 5,
),
child: Text(
'Login',
style: TextStyle(color: Colors.white, fontSize: 16.0),
),
),
),
verticalSpaceMedium,
Container(
width: 200.0,
child: TextButton(
style: TextButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blue,
elevation: 5,
),
onPressed: () => Navigator.pushNamed(context, SignupPage.id),
child: Text(
'Create Account',
),
),
),
verticalSpaceMedium,
Text(error, style: TextStyle(color: Colors.red, fontSize: 14),)
],
),
)
],
),
),
),
);
The above code works fine but want to add the validator that I have explained above.
See https://pub.dev/packages/email_validator. Do not attempt to write a regex to validate an email address. It will most certainly leave out some perfectly valid email forms that you might not have encountered yet. For example, both fred&barney#stonehenge.com (my autoresponder) and *#qz.to (an address a friend used for years, but now uses *#unspecified.example.com) are valid. Email Validator package correctly accepts both of those.
I have used a form inside a SingleChildScrollView, and everything works fine:
Form :
Everything works fine,
I have used this code
#override
Widget build(BuildContext context) {
double stackHeight = MediaQuery.of(context).size.height/4;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: SingleChildScrollView(
child :SafeArea(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [const Color(0xFF3023AE), const Color(0xFFC86DD7)])),
child: Column(
children: <Widget>[
Container(
height: stackHeight*2.6,
child: IntroViewsFlutter(
pages,
onTapDoneButton: (){
Navigator.pop(context);
},
showSkipButton: false,
pageButtonsColor: btnColors,
),
),
Container(
height: stackHeight*1.4,
child: bottomHomePage(),
color: pageColor,
width: width,
),
],
),
)
),
)
);
but when errors appear, this is what happens :
I have tried many things, I have heard about layoutBuilder, but dont know if it will work for me or there are another solutions that can adapt to runtime events.
UPDATE :
the problem was coming only of using an expanded inside a column : here we are the code again :
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Center (
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [const Color(0xFF3023AE), const Color(0xFFC86DD7)])),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 70.0, bottom: 20.0),
child: Text(
"C'est parti !",
style: TextStyle(fontSize: 32, color: Colors.white),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
width: width_textFormField + 15.0,
child: Text(
" Avant de commencer, sache que pour utiliser pleinement ta BanKids tu devras demander à tes parents de s'inscrire pour te débloquer toutes les fonctionnalités",
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
textAlign: TextAlign.center,
)),
),
Container(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: Text(
"Client Bank ?",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
Container(
child: Row(
children: <Widget>[
Text(
"Oui",
style: TextStyle(color: Colors.white),
),
Radio(
value: 1,
activeColor: Colors.white,
groupValue: _grpVal,
onChanged: _handleRadioValueChange1,
),
],
)),
Container(
child: Row(
children: <Widget>[
Text(
"Non",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white),
),
Radio(
activeColor: Colors.white,
value: 2,
groupValue: _grpVal,
onChanged: _handleRadioValueChange1,
),
],
)),
],
)),
Container(
child: Column(
children: <Widget>[
customizedTextFormField(
hintText: "Nom",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Prénom",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Date de Naissance",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "CIN",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Email",
width: width_textFormField + 10.0,
txtColor: Colors.black)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
width: width_textFormField,
child: Row(
children: <Widget>[
Checkbox(
checkColor: Color(0xFF3023AE),
value: isCheck,
activeColor: Colors.white,
onChanged: _handleCheckBox,
),
Expanded(
child: Text(
"En continuant l'inscription, je déclare accepter ces conditions d'utilisations ",
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
//************ next work
Container(
width: 200,
height: 60,
margin: EdgeInsets.only(right: 8.0,bottom: 8.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
Button_with_icon(
backgroundColor: Color(0xFF7CB342),
textColor: Colors.white,
textButton: "Continuer",
onPressed: (){
if(_formKey.currentState.validate()){
print("say l3adab");
}
},
icon: Icon(Icons.arrow_forward_ios),
),
],
)
),
],
),
)),
),
)
),
);
The problem was only of using an expanded inside my form, so I have removed and removed the height and width that I have given to my container :
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Center (
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [const Color(0xFF3023AE), const Color(0xFFC86DD7)])),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 70.0, bottom: 20.0),
child: Text(
"C'est parti !",
style: TextStyle(fontSize: 32, color: Colors.white),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
width: width_textFormField + 15.0,
child: Text(
" Avant de commencer, sache que pour utiliser pleinement ta BanKids tu devras demander à tes parents de s'inscrire pour te débloquer toutes les fonctionnalités",
style: TextStyle(
fontSize: 14,
color: Colors.white,
),
textAlign: TextAlign.center,
)),
),
Container(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: Text(
"Client Bank ?",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
Container(
child: Row(
children: <Widget>[
Text(
"Oui",
style: TextStyle(color: Colors.white),
),
Radio(
value: 1,
activeColor: Colors.white,
groupValue: _grpVal,
onChanged: _handleRadioValueChange1,
),
],
)),
Container(
child: Row(
children: <Widget>[
Text(
"Non",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white),
),
Radio(
activeColor: Colors.white,
value: 2,
groupValue: _grpVal,
onChanged: _handleRadioValueChange1,
),
],
)),
],
)),
Container(
child: Column(
children: <Widget>[
customizedTextFormField(
hintText: "Nom",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Prénom",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Date de Naissance",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "CIN",
width: width_textFormField + 10.0,
txtColor: Colors.black),
customizedTextFormField(
hintText: "Email",
width: width_textFormField + 10.0,
txtColor: Colors.black)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
width: width_textFormField,
child: Row(
children: <Widget>[
Checkbox(
checkColor: Color(0xFF3023AE),
value: isCheck,
activeColor: Colors.white,
onChanged: _handleCheckBox,
),
Expanded(
child: Text(
"En continuant l'inscription, je déclare accepter ces conditions d'utilisations ",
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
//************ next work
Container(
width: 200,
height: 60,
margin: EdgeInsets.only(right: 8.0,bottom: 8.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
Button_with_icon(
backgroundColor: Color(0xFF7CB342),
textColor: Colors.white,
textButton: "Continuer",
onPressed: (){
if(_formKey.currentState.validate()){
print("say l3adab");
}
},
icon: Icon(Icons.arrow_forward_ios),
),
],
)
),
],
),
)),
),
)
),
);
put a column child on singlechildscrollview then create a row for each form element, and put those in expanded widget
SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Material(
elevation: 0,
child: Container(
padding: EdgeInsets.all(16),
child: Column(
children: <Widget>[
Column(
children: <Widget>[
Form(
onChanged: () {
_tcFormKey.currentState.validate();
if (_tcController.text.length != 11) {
setState(() {
tcValidated = false;
});
}
},
key: _tcFormKey,
child: TextFormField(
controller: _tcController,
maxLength: 11,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly,
],
validator: (String value) {
if (value.isEmpty) {
return 'Zorunlu alan';
}
if (value.length != 11) {
return 'Kimlik numarası 11 haneli olmalıdır';
}
if (value.length == 11 && !Functions.validateTC(value.toString())) {
return 'Hatalı TC. Kimlik No';
} else {
setState(() {
tcValidated = true;
});
}
},
keyboardType: TextInputType.numberWithOptions(),
decoration: InputDecoration(
counterText: '',
suffixIcon: tcValidated
? Icon(
Icons.check,
color: Colors.green,
)
: Text(''),
labelText: 'TC Kimlik No',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black26, width: 1),
),
),
),
),
SizedBox(
height: 12,
),
Form(
onChanged: () {
_uavtFormKey.currentState.validate();
},
key: _uavtFormKey,
child: TextFormField(
controller: _uavtController,
maxLength: 11,
inputFormatters: <TextInputFormatter>[WhitelistingTextInputFormatter.digitsOnly],
validator: (String value) {
if (value.isEmpty) {
return 'Zorunlu alan';
}
},
keyboardType: TextInputType.numberWithOptions(),
decoration: InputDecoration(
labelText: 'UAVT Adres Kodu',
suffixIcon: Icon(Icons.location_on),
counterText: '',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black26, width: 1),
),
),
),
),
SizedBox(
height: 12,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Form(
onChanged: () {
_adFormKey.currentState.validate();
},
key: _adFormKey,
child: TextFormField(
controller: _adController,
maxLength: 64,
validator: (String value) {
if (value.isEmpty) {
return 'Zorunlu alan';
}
},
inputFormatters: [
WhitelistingTextInputFormatter(
RegExp("[a-zA-ZĞğÜüÖöŞşçÇİı]"),
),
],
decoration: InputDecoration(
labelText: 'Ad',
counterText: '',
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black26,
width: 1,
),
),
),
),
),
),
SizedBox(
width: 8,
),
Expanded(
child: Form(
onChanged: () {
_soyadFormKey.currentState.validate();
},
key: _soyadFormKey,
child: TextFormField(
controller: _soyadController,
maxLength: 64,
validator: (String value) {
if (value.isEmpty) {
return 'Zorunlu alan';
}
},
inputFormatters: [
WhitelistingTextInputFormatter(
RegExp("[a-zA-ZĞğÜüÖöŞşçÇİı]"),
),
],
decoration: InputDecoration(
labelText: 'Soyad',
counterText: '',
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black26,
width: 1,
),
),
),
),
),
),
],
),
SizedBox(
height: 12,
),
Form(
onChanged: () {
_telFormKey.currentState.validate();
},
key: _telFormKey,
child: TextFormField(
controller: _telController,
maxLength: 10,
validator: (String val) {
if (val.isEmpty) {
return 'Zorunlu alan';
}
},
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly,
],
keyboardType: TextInputType.numberWithOptions(),
decoration: InputDecoration(
errorStyle: TextStyle(color: Colors.red),
hintText: '10 Haneli Telefon Numarası',
labelText: 'Telefon Numarası',
hintStyle: TextStyle(color: Colors.black38),
suffixIcon: Icon(Icons.phone_iphone),
counterText: '',
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black26,
width: 1,
),
),
),
),
),
SizedBox(
height: 12,
),
OutlineButton(
highlightColor: Colors.transparent,
splashColor: Colors.blue.shade50,
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(2)),
borderSide: BorderSide(color: !emptyDateError ? Colors.black26 : Colors.red),
onPressed: () {
selectedBDate = '';
DatePicker.showDatePicker(context,
showTitleActions: true,
minTime: DateTime(1910, 1, 1),
maxTime: DateTime.now(),
onChanged: (date) {}, onConfirm: (date) {
int y = int.parse(DateFormat.y().format(date));
int m = int.parse(DateFormat.M().format(date));
int d = int.parse(DateFormat.d().format(date));
setState(() {
selectedBDate = '$y-$m-$d';
emptyDateError = false;
});
print('confirm $date');
}, currentTime: DateTime.now(), locale: LocaleType.tr);
},
child: Padding(
padding: const EdgeInsets.only(left: 2, right: 2, top: 16, bottom: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Icon(Icons.calendar_today, size: 16,),
Padding(
padding: const EdgeInsets.only(top: 2),
child: Text(
' Doğum Tarihi',
style: TextStyle(fontSize: 15),
),
),
],
),
),
selectedBDate != ''
? Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Text('$selectedBDate'),
),
)
: emptyDateError
? Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Text(
'Zorunlu Alan',
style: TextStyle(color: Colors.red),
),
),
)
: Container(),
],
),
),
),
SizedBox(
height: 12,
),
Form(
onChanged: () {
_mailFormKey.currentState.validate();
},
key: _mailFormKey,
child: TextFormField(
controller: _mailController,
validator: (String val) {
if (val.isEmpty) {
return 'Zorunlu alan';
}
if(!Functions.isEmail(val)){
return 'Geçerli bir mail adresi belirtiniz';
}
},
decoration: InputDecoration(
suffixIcon: Icon(Icons.mail_outline),
labelText: 'Mail Adresi',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 1),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black26, width: 1),
),
),
),
),
SizedBox(
height: 12,
),
Material(
elevation: 8,
shadowColor: Colors.green,
borderRadius: BorderRadius.circular(4),
color: Colors.green,
child: InkWell(
onTap: () {
if (_tcController.text != '' &&
_uavtController.text != '' &&
_adController.text != '' &&
_soyadController.text != '' &&
_telController.text != '' &&
_mailController.text != '' &&
selectedBDate != '' &&
Functions.validateTC(_tcController.text)) {
_tcFormKey.currentState.validate();
_uavtFormKey.currentState.validate();
_adFormKey.currentState.validate();
_soyadFormKey.currentState.validate();
_telFormKey.currentState.validate();
_mailFormKey.currentState.validate();
print(_telController.text.length);
var oprt = _telController.text.trim().split(' ')[0];
oprt = oprt.replaceAll('(', '');
oprt = oprt.replaceAll(')', '');
print(oprt);
_pageController.nextPage(duration: Duration(milliseconds: 300), curve: Curves.ease);
} else {
if (selectedBDate == '') {
setState(() {
emptyDateError = true;
});
}
_tcFormKey.currentState.validate();
_uavtFormKey.currentState.validate();
_adFormKey.currentState.validate();
_soyadFormKey.currentState.validate();
_telFormKey.currentState.validate();
_mailFormKey.currentState.validate();
}
},
child: Container(
width: double.infinity,
height: 48,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'İlerle ',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 18),
),
Icon(
Icons.arrow_forward,
color: Colors.white,
),
],
),
),
),
),
),
],
),
],
),
),
),
),
Basically I have a login page where I first segement into 2 container with one covers 55% and 45% of the screen. Then on top of these 2 container I add one more container with top 40% of the screen size and in it I have one more container which hold my user name and password text field. So on the design wise I am ok.
Now the issue when the keyboard comes the password field is totally not visible. First I just had stack then I did google and some suggest to put the Scaffold and add this line resizeToAvoidBottomPadding: false, but seems does not work for me either too.
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Container(
child: Stack(
children: <Widget>[
// The containers in the background
new Column(
children: <Widget>[
new Container(
height: MediaQuery.of(context).size.height * .55,
//color: Colors.blue,
decoration: new BoxDecoration(
image: new DecorationImage(image: new AssetImage("lib/assets/cbg.png"), fit: BoxFit.cover,),
),
),
new Container(
height: MediaQuery.of(context).size.height * .45,
color: Colors.white,
)
],
),
// The card widget with top padding,
// incase if you wanted bottom padding to work,
// set the `alignment` of container to Alignment.bottomCenter
new Container(
alignment: Alignment.topCenter,
padding: new EdgeInsets.only(
top: MediaQuery.of(context).size.height * .40,
right: 20.0,
left: 20.0),
child: new Container(
height: MediaQuery.of(context).size.height * .45,
width: MediaQuery.of(context).size.width,
child: new Card(
color: Colors.white,
elevation: 4.0,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 40.0),
child: Column(
children: <Widget>[
SizedBox(height: MediaQuery.of(context).size.height * .05),
new TextFormField(
decoration: new InputDecoration(
labelText: "Enter Email",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(10.0),
borderSide: new BorderSide(
color: Colors.blue
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Email cannot be empty";
}else{
return null;
}
},
keyboardType: TextInputType.emailAddress,
style: new TextStyle(
fontFamily: "Poppins",
),
),
SizedBox(height: MediaQuery.of(context).size.height * .05),
new TextFormField(
decoration: new InputDecoration(
labelText: "Enter Password",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(10.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Password cannot be empty";
}else{
return null;
}
},
keyboardType: TextInputType.emailAddress,
style: new TextStyle(
fontFamily: "Poppins",
),
),
],
),
)
),
),
),
new Container(
alignment: Alignment.topCenter,
padding: new EdgeInsets.only(
top: MediaQuery.of(context).size.height * .80,
right: 50.0,
left: 50.0),
child: new FlatButton(
color: Colors.red,
child: Text("Press Me"),
onPressed: () {},
),
),
new Container(
alignment: Alignment.topCenter,
padding: new EdgeInsets.only(
top: MediaQuery.of(context).size.height * .90,
right: 50.0,
left: 50.0),
child: new FlatButton(
color: Colors.red,
child: Text("Forgot Password ?"),
onPressed: () {},
),
)
],
)
)
);
}
}
After the changes the keyboard still appear a slight covering the textfield.
Can I achieve some
You should put all this inside a ListView, then when you open the keyboard the list will scroll up.
I'm 2 years late on this and you might find the solution already, but this is for someone who struggle to find the solution. (Include myself a couple a days ago)
To solve this, The "TextFormField" widget need another attribute called "scrollPadding".
TextFormField(
controller: controller,
scrollPadding: EdgeInsets.only(bottom:40), // THIS SHOULD SOLVE YOUR PROBLEM
decoration: InputDecoration(
labelText: title,
hintText: title,
filled: true,
fillColor: Colors.white,
enabledBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Colors.grey, width: 1.0),
),
border: const OutlineInputBorder(),
),
validator: (String? value) {
if (value == null || value.isEmpty) {
return title;
}
return null;
},
),
friends, I am thinking to make this type of view but I can't able to set the button overlapping like the given image I am using stack widget which is containing the text fields and the buttons as given image please check and help me out I also tried to use the center widgets as well but the view is coming as required in it also i had used the positioned widget but its getting button bottom of the screen like this but i need as the above image
MyLayoutDesign
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
MyAppState myAppState() => new MyAppState();
return myAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(home: new Scaffold(body: new Builder(
builder: (BuildContext context) {
return new Stack(
children: <Widget>[
new Image.asset(
'assets/images/bg.png',
fit: BoxFit.cover,
),
new Center(
child: new Container(
child: new Card(
color: Colors.white,
elevation: 6.0,
margin: EdgeInsets.only(right: 15.0, left: 15.0),
child: new Wrap(
children: <Widget>[
Center(
child: new Container(
margin: EdgeInsets.only(top: 20.0),
child: new Text(
'Login',
style: TextStyle(
fontSize: 25.0, color: secondarycolor),
),
),
),
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter email',
labelText: 'Enter Your Email address',
),
keyboardType: TextInputType.emailAddress,
),
),
new ListTile(
leading: const Icon(Icons.lock),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter password',
labelText: 'Enter Your Password',
),
keyboardType: TextInputType.emailAddress,
obscureText: true,
),
),
Container(
margin: EdgeInsets.only(top: 10.0, bottom: 15.0),
child: Center(
child: Text(
"FORGOT PASSWORD",
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0),
),
),
),
Center(
child: Container(
margin: EdgeInsets.only(bottom: 40.0, top: 10.0),
child: Text.rich(
TextSpan(
children: const <TextSpan>[
TextSpan(
text: 'NEW USER ? ',
style: TextStyle(
fontSize: 16.0, color: Colors.black)),
TextSpan(
text: 'REGISTER',
style: TextStyle(
fontSize: 16.0,
decoration: TextDecoration.underline,
color: Colors.black)),
],
),
),
),
),
],
),
),
),
),
new RaisedButton(
onPressed: () {
print('Login Pressed');
},
color: primarycolor,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
child: new Text('Login',
style: new TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold)),
),
],
);
},
)));
}
}
this is just one the many ways you can achieve the expected result.
In this case, i assume you know the height of the background.
Again, there are many ways to achieve what you want. There is nothing wrong with your code, you just have to get an understanding of how 'things' work in Flutter
Widget demo = Stack(
children: <Widget>[
//First thing in the stack is the background
//For the backgroud i create a column
Column(
children: <Widget>[
//first element in the column is the white background (the Image.asset in your case)
DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white
),
child: Container(
width: 300.0,
height: 400.0,
)
),
//second item in the column is a transparent space of 20
Container(
height: 20.0
)
],
),
//for the button i create another column
Column(
children:<Widget>[
//first element in column is the transparent offset
Container(
height: 380.0
),
Center(
child: FlatButton(
color: Colors.red,
child: Text("Press Me"),
onPressed: () {},
),
)
]
)
],
);
Here you can find your solution code below.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
MyAppState myAppState() => new MyAppState();
return myAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(home: new Scaffold(body: new Builder(
builder: (BuildContext context) {
return new Stack(
children: <Widget>[
new Image.asset(
'assets/images/bg.jpeg',
fit: BoxFit.fitWidth,
),
new Center(
child: new Container(
height: 370.0,
child: Container(
height:250.0,
child: new Card(
color: Colors.white,
elevation: 6.0,
margin: EdgeInsets.only(right: 15.0, left: 15.0),
child: new Wrap(
children: <Widget>[
Center(
child: new Container(
margin: EdgeInsets.only(top: 20.0),
child: new Text(
'Login',
style: TextStyle(
fontSize: 25.0, color: Colors.red),
),
),
),
new ListTile(
leading: const Icon(Icons.person),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter email',
labelText: 'Enter Your Email address',
),
keyboardType: TextInputType.emailAddress,
),
),
new ListTile(
leading: const Icon(Icons.lock),
title: new TextFormField(
decoration: new InputDecoration(
hintText: 'Please enter password',
labelText: 'Enter Your Password',
),
keyboardType: TextInputType.emailAddress,
obscureText: true,
),
),
Container(
margin: EdgeInsets.only(top: 10.0, bottom: 15.0),
child: Center(
child: Text(
"FORGOT PASSWORD",
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 16.0),
),
),
),
Center(
child: Container(
margin: EdgeInsets.only(bottom: 40.0, top: 10.0),
child: Text.rich(
TextSpan(
children: const <TextSpan>[
TextSpan(
text: 'NEW USER ? ',
style: TextStyle(
fontSize: 16.0, color: Colors.black)),
TextSpan(
text: 'REGISTER',
style: TextStyle(
fontSize: 16.0,
decoration: TextDecoration.underline,
color: Colors.black)),
],
),
),
),
),
Padding(padding: EdgeInsets.only(left: 120.0)),
],
),
),
),
padding: EdgeInsets.only(bottom: 30),
),
),
new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 310.0)),
RaisedButton(
onPressed: () {
print('Login Pressed');
},
color: Colors.green,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
child: new Text('Login',
style: new TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold)),
),
],
)
)
],
);
},
)));
}
}
#ibhavikmakwana propsed a better solution to your question. The other answers all depend on the size of the background and are not screen independent. They both create an invisible object above the button (either by adding a Container or a Padding).
I was having that question too and did not find your question first.
His simple solution is to wrap the button in a Positioned widget and give it a bottom of 0 or < 0.
Positioned(
child: FlatButton(
color: Colors.red,
child: Text("Press Me"),
onPressed: () {},
),
right: 0,
left: 0,
bottom: 0,
)
I found out that the "bottom" attribute set to 0 will offset the widget by exactly 0.5*height of the widget.