RenderBox was not laid out: flutter error - flutter

I'm new to flutter. I'm creating a login page. but now getting the below error in my code when I add remember me and forget password buttons into a Row Widget to display in one row. how to solve this. for your reference I have attached the full code and UI. login_screen full dart code , login_screen UI image
RenderBox was not laid out: _RenderListTile#c9c23
relayoutBoundary=up24 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart': Failed assertion: line 1982
pos 12: 'hasSize'
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.disabled,
child: Container(
margin: const EdgeInsets.all(20.0),
child: Column(
children: [
SizedBox(
height: 40,
),
TextFormField(
controller: emailEditingController,
enabled: true,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
hintText: "Email/ Username",
hintStyle: TextStyle(
color: textGrey, fontFamily: "Dubai", fontSize: 14),
),
validator: (String? UserName) {
if (UserName != null && UserName.isEmpty) {
return "Email can't be empty";
}
return null;
},
onChanged: (String? text) {
email = text!;
// print(email);
},
onSaved: (value) {
loginUserData['email'] = value!;
},
),
SizedBox(
height: 20,
),
TextFormField(
controller: passwordEditingController,
obscureText: _isObscure,
enabled: typing,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
),
suffixIcon: IconButton(
icon: Icon(_isObscure
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
setState(() {
_isObscure = !_isObscure;
});
}),
hintText: "Password",
hintStyle: TextStyle(
color: textGrey, fontFamily: "Dubai", fontSize: 14)),
validator: (String? Password) {
if (Password != null && Password.isEmpty) {
return "Password can't be empty";
}
return null;
},
onChanged: (String? text) {
password = text!;
// print(password);
},
onSaved: (value) {
loginUserData['password'] = value!;
},
),
// this is where I got an error.
Row(
// mainAxisAlignment: MainAxisAlignment.start,
children: [
CheckboxListTile(
title: const Text(
"Remember Me",
style: TextStyle(
color: textGrey, fontFamily: "Dubai", fontSize: 14),
),
value: checkedValue,
onChanged: (newValue) {
FocusManager.instance.primaryFocus?.unfocus();
setState(() {
if (isLoading != true) {
checkedValue = newValue!;
print(newValue);
}
});
},
contentPadding: EdgeInsets.only(left: 0, top: 0),
controlAffinity:
ListTileControlAffinity.leading, // <-- leading Checkbox
),
SizedBox(
width: 5,
),
TextButton(
child: Text(
"Forget Password",
style: TextStyle(
color: textGrey, fontFamily: "Dubai", fontSize: 14),
),
onPressed: () {
//Get.to(ForgetPassword());
},
)
],
),
SizedBox(
height: 30,
),
isLoading
? SpinKitDualRing(
color: mainGreen,
size: 40,
)
: GestureDetector(
child: MainButton("Login"),
onTap: () {
},
),
SizedBox(
height: 30,
),
GestureDetector(
child: MainButton("Signup"),
onTap: () {
},
),
],
),
),
),
);
}

The issue is coming from CheckboxListTile while it is inside the Row,
Wrap CheckboxListTile with Expanded widget, it will get available width inside row.
Row(
children: [
Expanded(
child: CheckboxListTile(
More about Expanded.

Related

How to do ElevatedButton disabled?

I want the button to be inactive until 10 characters are entered in the field. When 10 characters were entered, the button was active. And when it is inactive it is gray, and when it is active it is blue. How can I do that?
Here is the input code with the button:
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Padding(
padding: EdgeInsets.fromLTRB(
20, MediaQuery.of(context).size.height * 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
onChanged: (String value) {
setState(() {
_showIcon = value.isNotEmpty;
});
},
controller: _inputController,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2.0),
),
hintText: "(1201) 565-0123 ",
hintStyle: TextStyle(color: Colors.grey, fontSize: 15),
helperText: 'Enter your phone number',
helperStyle: TextStyle(color: Colors.grey, fontSize: 15),
suffixIcon: _showIcon
? IconButton(
onPressed: () {
setState(() {
_inputController.clear();
_showIcon = false;
});
},
icon: const Icon(Icons.close, color: Colors.grey),
) : null,
),
keyboardType: TextInputType.number,
inputFormatters: [maskFormatter],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
},
child: const Icon(Icons.arrow_forward_rounded, size: 25),
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(15)
)
),
],
)
],
),
),
),
);
}
}
You can call setState(() {}); on onChanged to update the UI, or add listener on _inputController.
ElevatedButton(
onPressed:
_inputController.text.length < 10 ? null : () {},
...
Passing onPressed:null will provide disable state.
Updating UI can be done
TextField(
onChanged: (String value) {
setState(() {});
},
....)
Or
late final TextEditingController _inputController;
#override
void initState() {
super.initState();
_inputController = TextEditingController()
..addListener(() {
setState(() {});
});
}
Use a variable like isEnabled and passing null to the onPress function will disable the button.
bool isEnabled=false;
void callbackfunction(){
// add your logic here.
}
....
....
TextField(
onChanged: (String value) {
if (value.length == 10){
setState(()=> isEnabled = true;)
}
else{
isEnabled=false;
}
setState(() {
_showIcon = value.isNotEmpty;
});
},
....
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: isEnabled ? callbackfunction : null,
child: const Icon(Icons.arrow_forward_rounded, size: 25),
style: ElevatedButton.styleFrom(
color: isEnabled ? Colors.blue : Colors.grey,
shape: CircleBorder(),
padding: EdgeInsets.all(15)
)
),
],
)
],
),
P.S Please check the syntax I have just provided you the concept.

Flutter PIN Verification Countdown

I made a pin verification with countdown using the timer_count_down package. What I'm trying to do is when the countdown is finished, it shows a text saying "Resend PIN" to resend the PIN to email and starts the countdown again.
Here is my Login.dart code snippet when I enter my email address it sends a PIN code to my email :
...
Form(
key: _formKey,
child: TextFormField(
cursorColor: Color(0xFF2481CF),
autofocus: true,
validator: (value) {
if (value == null || value.isEmpty || !EmailValidator.validate(value.trim())) {
return 'Email is not valid!';
}
return null;
},
controller: _controller,
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFF2481CF)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFF2481CF)),
),
labelText: 'Enter your email :',
labelStyle: TextStyle(
color: Color(0xFF2481CF)
)
),
style: TextStyle(
fontSize: 19.0,
height: 1.3,
),
),
),
...
floatingActionButton: FloatingActionButton(
// onPressed: _submit,
onPressed: () {
if (_formKey.currentState!.validate()) {
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 20,),
Text('PIN code will be sent to'),
SizedBox(height: 10,),
Text(_controller.text,
style: TextStyle(
fontWeight: FontWeight.bold
),),
SizedBox(
height: 30,
),
Text('Is this OK or would you like to edit the email address?'),
],
),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Edit',
style: TextStyle(
color: Color(0xFF2481CF)
),),
),
TextButton(
onPressed: () {
//kirim email
sendEmail(_controller.text.trim());
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => PinVerification(_controller.text.trim())),
);
},
child: const Text('Verify',
style: TextStyle(
color: Color(0xFF2481CF)
),),
),
],
),
);
};
},
child: const Icon(Icons.send),
),
And for the PinVerification.dart :
Widget onlySelectedBorderPinPut() {
final BoxDecoration pinPutDecoration = BoxDecoration(
color: const Color.fromRGBO(235, 236, 237, 1),
borderRadius: BorderRadius.circular(5.0),
);
return Form(
key: _formKey,
child: Column(
children: [
SizedBox(
height: 50,
),
Text(
'Enter 6 digit code we sent to your email.',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey),
),
SizedBox(
height: 30,
),
GestureDetector(
onLongPress: () {
print(_formKey.currentState?.validate());
},
child: PinPut(
validator: (s) {
if (s != null && s.contains('1')) return null;
return 'NOT VALID';
},
useNativeKeyboard: true,
autovalidateMode: AutovalidateMode.always,
withCursor: true,
fieldsCount: 6,
fieldsAlignment: MainAxisAlignment.spaceAround,
textStyle: const TextStyle(fontSize: 25.0, color: Colors.black),
eachFieldMargin: EdgeInsets.all(0),
eachFieldWidth: 45.0,
eachFieldHeight: 55.0,
onSubmit: (String pin) => postRequest(pin),
focusNode: _pinPutFocusNode,
controller: _pinPutController,
submittedFieldDecoration: pinPutDecoration,
selectedFieldDecoration: pinPutDecoration.copyWith(
color: Colors.white,
border: Border.all(
width: 2,
color: const Color.fromRGBO(160, 215, 220, 1),
),
),
followingFieldDecoration: pinPutDecoration,
pinAnimationType: PinAnimationType.scale,
),
),
SizedBox(
height: 20,
),
Countdown(
seconds: 20,
build: (_, double time) =>
RichText(
text: TextSpan(
text: 'Send PIN again in ',
style: TextStyle(
color: Theme.of(context).inputDecorationTheme.labelStyle?.color
),
children: <TextSpan>[
TextSpan(
text: time.toString(),
style: TextStyle(
color: Color(0xFF2481CF),
fontWeight: FontWeight.bold
)),
TextSpan(text: ' sec',
style: TextStyle(
color: Theme.of(context).inputDecorationTheme.labelStyle?.color
))
]
),
),
onFinished: () {
},
),
],
),
);
}
This is the screenshot for my PinVerification.dart:
Any solutions?
Created custom timer It worked for me
late Timer _timer;
int _start = 60;
void startTimer() {
const oneSec = const Duration(seconds: 1);
_timer = new Timer.periodic(
oneSec,
(Timer timer) {
if (_start == 0) {
setState(() {
timer.cancel();
});
} else {
setState(() {
_start--;
});
}
},
);
}
#override
void initState() {
super.initState();
startTimer();
}
#override
void dispose() {
super.dispose();
_timer.cancel();
errorController!.close();
}
And inside widget check condition as follows:
_start != 0
? Row(
// mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
"Resend Code in",
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontWeight: FontWeight.bold,
fontSize: 16),
),
const SizedBox(width: 10),
Text(
_start.toString(),
style: TextStyle(
color: MyTheme.yellow,
fontWeight: FontWeight.bold,
fontSize: 20),
),
],
)
: YourWidget() // your widget here
When the Resend Otp is clikced reset the timer is as follows:
setState(() {
_start = 60;
startTimer();
});

SingleChildScrollView is not scrolling with Stack Widget Flutter

Here when I type inside text fields Keyboard covers the Login button. So I need to scroll down to the Login button when typing. I tried wrapping LayoutBuilder with SingleChildScrollView and tried using Positioned widget inside Stack but nothing solved my issue. And I set physics to AlwaysScrollableScrollPhysics() inside SingleChildScrollView but it also didn't solve the problem. I can't figure out what I've done wrong. I would be grateful if anyone can help me with this issue
Here's my code
Material(
child: SingleChildScrollView(
child: Stack(
overflow: Overflow.clip,
children: <Widget>[
Image.asset(
'assets/login-screen-img.jpg'
),
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 220.0, 16.0, 0),
child: Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 24.0),
child: Form(
//associating global key with the form(It keeps track of the form)
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Email', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
TextFormField( // email field
cursorColor: Colors.brown[500],
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.brown[500])
),
//hintText: 'Enter your Email'
),
// validation
validator: (email) => email.isEmpty ? 'Enter the email' : null,
onChanged: (emailInput) {
setState(() {
email = emailInput;
});
},
),
SizedBox(height: 16.0),
Text('Password', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
TextFormField( // password field
cursorColor: Colors.brown[500],
decoration: InputDecoration(
//hintText: 'Enter your Password'
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.brown[500])
)
),
// validation
validator: (password) => password.length < 6 ? 'Password must be more than 6 characters' : null,
obscureText: true, // hide when type
onChanged: (passwordInput) {
setState(() {
password = passwordInput;
});
},
),
SizedBox(height: 48.0,),
Center(
child: RaisedButton( // login button
child: Text('LOG IN', style: TextStyle(fontSize: 16.0, color: Colors.white),),
color: Colors.brown[500],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25)
),
padding: EdgeInsets.fromLTRB(66.0, 16.0, 66.0, 16.0),
onPressed: () async {
if(_formKey.currentState.validate()) {
// show loading screen
setState(() {
loading = true;
});
dynamic result = await _auth.signInWithEmailAndPassword(email, password);
if(result == null) {
// stop showing loading screen/widget
setState(() {
loading = false;
});
// show an error message
Fluttertoast.showToast(
msg: 'Could not sign in!',
toastLength: Toast.LENGTH_SHORT,
);
}
}
},
),
),
SizedBox(height: 24.0),
Center(child: Text('Don\'t have and account ?' )),
SizedBox(height: 16.0,),
Center(
child: FlatButton( // sign up button
child: Text('SIGN UP', style: TextStyle(fontSize: 16.0, color: Colors.brown[500] )),
onPressed: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => SignUp()
));
},
),
)
],
),
),
),
),
)
],
),
),
);
Screenshot of my UI
Here I found that the issue is with the height of the stack. As #sajithlakmal mentioned in the comments, height of the stack is small and there is nothing to scroll. But in my case, I don't want to make an extra height than the screen height because this is just a login screen. I could easily solve the issue by replacing Material widget with Scaffold. inside the body of the Scaffold gives the required height when typing and able to scroll down.
Here's the working code.
Scaffold(
body: SingleChildScrollView(
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Image.asset(
'assets/login-screen-img.jpg',
alignment: Alignment.topCenter,
),
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 220.0, 16.0, 0),
child: Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 24.0),
child: Form(
//associating global key with the form(It keeps track of the form)
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Email', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
TextFormField( // email field
cursorColor: Colors.brown[500],
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.brown[500])
),
//hintText: 'Enter your Email'
),
// validation
validator: (email) => email.isEmpty ? 'Enter the email' : null,
onChanged: (emailInput) {
setState(() {
email = emailInput;
});
},
),
SizedBox(height: 16.0),
Text('Password', style: TextStyle(fontSize: 14.0, color: Colors.grey),),
TextFormField( // password field
cursorColor: Colors.brown[500],
decoration: InputDecoration(
//hintText: 'Enter your Password'
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.brown[500])
)
),
// validation
validator: (password) => password.length < 6 ? 'Password must be more than 6 characters' : null,
obscureText: true, // hide when type
onChanged: (passwordInput) {
setState(() {
password = passwordInput;
});
},
),
SizedBox(height: 48.0,),
Center(
child: RaisedButton( // login button
child: Text('LOG IN', style: TextStyle(fontSize: 16.0, color: Colors.white),),
color: Colors.brown[500],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25)
),
padding: EdgeInsets.fromLTRB(66.0, 16.0, 66.0, 16.0),
onPressed: () async {
if(_formKey.currentState.validate()) { // check validation
// show loading screen
setState(() {
loading = true;
});
dynamic result = await _auth.signInWithEmailAndPassword(email, password);
if(result == null) {
// stop showing loading screen/widget
setState(() {
loading = false;
});
// show an error message
Fluttertoast.showToast(
msg: 'Could not sign in!',
toastLength: Toast.LENGTH_SHORT,
);
}
}
},
),
),
SizedBox(height: 24.0),
Center(child: Text('Don\'t have and account ?' )),
SizedBox(height: 16.0,),
Center(
child: FlatButton( // sign up button
child: Text('SIGN UP', style: TextStyle(fontSize: 16.0, color: Colors.brown[500] )),
onPressed: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => SignUp()
));
},
),
)
],
),
),
),
),
)
],
),
),
);

Validating TextformField with two different key in Flutter

I'm trying to validate two different TextFormFields in two widgets (One for Email, another one for password) with a single _formkey in a flutter. it gave me this error: Multiple widgets used the same GlobalKey. So defined two _formkey but the problem is Flutter form validators don't validate, simultaneously:
class _RegisterState extends State<Register> {
String email = "";
String password = "";
String error = "";
final _formKey1 = GlobalKey<FormState>();
final _formKey2 = GlobalKey<FormState>();
// bool _rememberMe = false;
Widget _buildEmailTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Email',
style: kLabelStyle,
),
SizedBox(height: 10.0),
Form(
key: _formKey1,
child: Container(
alignment: Alignment.centerLeft,
decoration: kBoxDecorationStyle,
height: 60.0,
child: TextFormField(
validator: (value) => value.isEmpty ? "Enter an Email" : null,
onChanged: (value) {
setState(() {
email = value;
});
},
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.email,
color: Colors.white,
),
hintText: 'Enter your Email',
hintStyle: kHintTextStyle,
),
),
),
),
],
);
}
Widget _buildPasswordTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Password',
style: kLabelStyle,
),
SizedBox(height: 10.0),
Form(
key: _formKey2,
child: Container(
alignment: Alignment.centerLeft,
decoration: kBoxDecorationStyle,
height: 60.0,
child: TextFormField(
validator: (value) =>
value.length < 6 ? "More than 6 Character" : null,
onChanged: (value) {
setState(() {
password = value;
});
},
obscureText: true,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.lock,
color: Colors.white,
),
hintText: 'Enter your Password',
hintStyle: kHintTextStyle,
),
),
),
),
],
);
}
and then :
onPressed: () async {
if (_formKey1.currentState.validate() &&
_formKey2.currentState.validate()) {
dynamic result =
await _auth.signUpWithEmailandPassword(email, password);
if (result == null) {
setState(() => error = "Something is wrong");
}
}
},
Just remember that you need one Form Widget above in the widget Tree.
And thus you can use the _formKey to validate multiple TextFormField below in the Widget Tree.
Modified Code
class _RegisterPageState extends State<RegisterPage> {
String email = "";
String password = "";
String error = "";
final _formKey1 = GlobalKey<FormState>();
// final _formKey2 = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Form(
key: _formKey1,
child: Container(
child: Column(
children: [
_buildEmailTF(),
SizedBox(
height: 20,
),
_buildPasswordTF(),
FlatButton(
onPressed: () async {
if (_formKey1.currentState.validate()) {
// dynamic result = await _auth.signUpWithEmailandPassword(
// email, password);
// if (result == null) {
// setState(() => error = "Something is wrong");
// }
print('DOne Working');
}
},
child: Text(
'Done',
))
],
),
),
),
);
}
// bool _rememberMe = false;
Widget _buildEmailTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Email',
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 60.0,
child: TextFormField(
validator: (value) => value.isEmpty ? "Enter an Email" : null,
onChanged: (value) {
setState(() {
email = value;
});
},
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.email,
color: Colors.white,
),
hintText: 'Enter your Email',
),
),
),
],
);
}
Widget _buildPasswordTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Password',
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 60.0,
child: TextFormField(
validator: (value) =>
value.length < 6 ? "More than 6 Character" : null,
onChanged: (value) {
setState(() {
password = value;
});
},
obscureText: true,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.lock,
color: Colors.white,
),
hintText: 'Enter your Password',
),
),
),
],
);
}
}
I/flutter (24750): DOne Working

Flutter SingleChildScrollView widget is pushing the whole container to the top and adding a chunk of white background

When I add the SingleChildScrollView widget, the whole container just goes up and there's a box of white background at the bottom as shown in the screenshot. I tried removing the whole padding including the bottom and that didn't change anything. I'm not really sure what to do. Any help would be appreciated. Screenshot of the screen
Widget build(BuildContext context) {
final bottom = MediaQuery.of(context).viewInsets.bottom;
// If we're loading then return the loading screen, otherwise the
// scaffold with the register screen
return loading ? Loading() : Scaffold (
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: SingleChildScrollView(
child: Container (
padding: EdgeInsets.fromLTRB(60.0, 0, 60, bottom),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/register_background.png'),
fit: BoxFit.fill,
),
),
child: Form (
key: _formKey,
child: Column (
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: MediaQuery.of(context).size.height * 0.04),
Image.asset('assets/logo.png'),
SizedBox(height: MediaQuery.of(context).size.height * 0.08),
Text(
"Register",
style: TextStyle (
fontFamily: 'MuseoSans',
fontSize: 26.0,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(77, 72, 91, 1.0), //#4D485B
),
),
SizedBox(height: 12.0),
TextFormField (
textAlign: TextAlign.center,
validator: (val) {
// Regex checking to see if email is valid
if (val.isEmpty || !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(val)) {
return 'Enter a valid email address';
}
else {
return null;
}
},
onChanged: (val) {
setState(() {
email = val;
});
},
cursorColor: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
decoration: textInputDecoration.copyWith(hintText: 'Email'),
),
SizedBox(height: 12.0,),
TextFormField (
textAlign: TextAlign.center,
validator: (val) => val.isEmpty ? 'Field is required' : null,
onChanged: (val) {
setState(() {
name = val;
});
},
cursorColor: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
decoration: textInputDecoration.copyWith(hintText: 'Username'),
),
SizedBox(height: 12.0,),
TextFormField (
textAlign: TextAlign.center,
validator: (val) {
if (val.isEmpty) {
return 'Field is required';
}
else if (val.length < 8) {
return 'Password must be at least 8 characters';
}
else if (val != confirmPassword) {
return 'Passwords must match';
}
else {
return null;
}
},
onChanged: (val) {
setState(() {
password = val;
});
},
cursorColor: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
obscureText: true,
decoration: textInputDecoration.copyWith(hintText: 'Password'),
),
SizedBox(height: 12.0,),
TextFormField (
textAlign: TextAlign.center,
validator: (val) {
if (val.isEmpty) {
return 'Field is required';
}
else if (val != password) {
return 'Passwords must match';
}
else {
return null;
}
},
onChanged: (val) {
setState(() {
confirmPassword = val;
});
},
cursorColor: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
obscureText: true,
decoration: textInputDecoration.copyWith(hintText: 'Confirm password'),
),
SizedBox(height: 20.0,),
ButtonTheme(
minWidth: 120.0,
child: RaisedButton (
onPressed: () async {
if(_formKey.currentState.validate()) {
// At this point we're checking the database for data
setState(() => loading = true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password, name);
if (result is String) {
// Parsing the result to only get the error message
String actualError = result.substring(result.indexOf(",") + 1, result.indexOf("."));
setState(() {
error = actualError;
// If there are errors we want to go back to the register screen
// so loading is false
loading = false;
});
}
}
},
child: Text (
'Create User',
style: TextStyle(
color: Colors.white,
fontFamily: 'MuseoSans',
fontSize: 16.0,
),
),
color: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
SizedBox(height: 12.0),
GestureDetector (
child: Text (
'Already have an account? Sign In',
style: TextStyle (
color: Color.fromRGBO(101, 166, 218, 1.0), //#65A6DA
fontFamily: 'MuseoSans',
)
),
onTap: () {
widget.toggleView();
}
),
SizedBox(height: 12.0),
Text (
error,
style: TextStyle (
color: Color.fromRGBO(238, 107, 107, 1.0), //#EE6B6B
fontSize: 14.0,
fontFamily: 'MuseoSans'
),
textAlign: TextAlign.center,
),
],
),
),
),
),
);
}
you just need to set the outer container height equal to the mobile screen size using MediaQuery.of(context).size.height
return loading ? Loading() : Scaffold (
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: SingleChildScrollView(
child: Container (
// this will set the outer container size to the height of your screen
height: MediaQuery.of(context).size.height,
// Other properties
child: Form (
// code
),
),
),
);
}
Hope I solve your problem happy coding!