如果我犯了错误,这是我的第一个问题,请纠正我:)
编码:Android Studio 语言为:Flutter/Dart
问题:如何在单独的 toast/snack bar/flush bar 的 textformfield 下方显示错误消息?
问题视频链接:https ://youtu.be/4hJtR11o1GU
代码:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
//import 'package:video_player/video_player.dart';
class LoginForm extends StatefulWidget {
LoginForm(this.submitFn, this.isLoading);
final bool isLoading;
final void Function(
String email,
String password,
String mobile,
bool isLogin,
BuildContext ctx,
) submitFn;
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
String _userEmail = '';
String _userPassword = '';
String _userMobile = '';
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
widget.submitFn(
_userEmail.trim(),
_userPassword.trim(),
_userMobile.trim(),
_isLogin,
context
);
}
}
Widget _buildEmailTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: 50.0,
child: TextFormField(
key: ValueKey('email'),
validator: (value) { if (value.isEmpty || !value.contains('@')) {return
'enter a valid email';} return null;},
keyboardType: TextInputType.emailAddress,
style: TextStyle(color: Colors.white, fontFamily: 'OpenSans',),
decoration: InputDecoration(
isDense: true,
hintText: 'username@xyz.com',
hintStyle: TextStyle(color: Colors.white, ),
contentPadding: EdgeInsets.only(top: 14.0),
errorMaxLines: 1,
errorText: 'Null',
errorStyle: TextStyle(
color: Colors.transparent,
fontSize: 0,
),
prefixIcon: Icon(
Icons.email,
color: Colors.orange ,
),
),
onSaved:(value){_userEmail = value;},
),
),
],
);
}
Widget _buildMobileTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.centerLeft,
height: 50.0,
child: TextFormField(
key: ValueKey('mobile'),
validator: (value) { if (value.isEmpty || !value.contains('91') || value.length > 12 || value.length < 12) {
return '';} return null;},
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
errorMaxLines: 1,
errorText: 'Null',
errorStyle: TextStyle(
color: Colors.transparent,
fontSize: 0,
),
hintText: '91 xxx-xxx-xxxx',
hintStyle: TextStyle(color: Colors.white, ),
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.phone_android,
color: Colors.orange,
),
),
onSaved:(value){_userMobile = value;},
),
),
],
);
}
Widget _buildPasswordTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 60.0,
child: TextFormField(
key: ValueKey('password'),
validator: (value) {if (value.isEmpty || value.length < 7) {
return '';} return null;},
obscureText: true,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
errorMaxLines: 1,
errorText: 'Null',
errorStyle: TextStyle(
color: Colors.transparent,
fontSize: 0,
),
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.lock,
color: Colors.orange,
),
hintText: 'Password',
hintStyle: TextStyle(color: Colors.white, )
),
onSaved:(value){
_userPassword = value;
},
),
),
],
);
}
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
width: double.infinity,
child: RaisedButton(
onPressed: _trySubmit,
elevation: 5.0,
padding: EdgeInsets.all(15.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
color: Colors.white,
child: Text(_isLogin ? 'Login In' : 'Sign Up',
style: TextStyle(
color: Colors.orange,
letterSpacing: 1.5,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
),
);
}
Widget _buildSignUpWithText() {
return Column(
children: <Widget>[
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(_isLogin ? 'Sign Up With An Email Account' : 'I Already Have An Account',
style: TextStyle(
color: Colors.orange,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
SizedBox(height: 20.0),
Text(
'- OR -',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
);
}
Widget _buildSocialBtn(Function onTap, AssetImage logo) {
return GestureDetector(
onTap: (){
setState(() {
});
_isLogin = !_isLogin;
},
child: Container(
height: 60.0,
width: 60.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black26,
offset: Offset(0, 2),
blurRadius: 6.0,
),
],
image: DecorationImage(
image: logo,
),
),
),
);
}
Widget _buildSocialBtnRow() {
return Padding(
padding: EdgeInsets.symmetric(vertical: 30.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildSocialBtn(
() => print('Sign Up with Google'),
AssetImage(
'assets/logos/google.jpg',
),
),
],
),
);
}
Widget _buildHomeChefSignUp() {
return GestureDetector(onTap: () => print('Chef\'s Sign Up Process'),
child: RichText(
text: TextSpan(
children: [
TextSpan(text: 'Passionate About Cooking ? ',
style: TextStyle(
color: Colors.white,
fontSize: 12.0,
fontWeight: FontWeight.w400,
),),
TextSpan(text: 'Join Us',
style: TextStyle(
color: Colors.orange,
fontSize: 12.0,
fontWeight: FontWeight.w400,
),),
])),
);
}
@override
Widget build(BuildContext context) {
//Keeps Back Ground Fixed even with Keyboard Opened
return Scaffold(resizeToAvoidBottomPadding: false,
//Top Status Bar Overlay Dark or Light
body: AnnotatedRegion<SystemUiOverlayStyle>(value: SystemUiOverlayStyle.light,
child: GestureDetector(onTap: ()=>FocusScope.of(context).unfocus(),
//Main Tree holding All the necessary Containers
child: Stack(children: <Widget>[
//Holds the background Video
Container(),
//Creates a black overlay to the background
Container(
height: double.infinity,
color: Colors.black.withAlpha(120),),
//Hold the Login Form
Container(
height: double.infinity,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 40.0, vertical: 100.0,),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Mother\'s Kitchen',
style: TextStyle(
color: Colors.orange,
fontFamily: 'MomsFonts',
fontSize: 40.0,
fontWeight: FontWeight.bold,),),
SizedBox(height: 10.0),
Text(
'Mumbai\'s First & Only Home Cooked Delivery Service',
style: TextStyle(
color: Colors.orange,
fontFamily: 'OpenSans',
fontSize: 12.0,
fontWeight: FontWeight.bold,),),
SizedBox(height: 30.0),
_buildEmailTF(),
SizedBox(height: 10.0,),
if(!_isLogin)
_buildMobileTF(),
_buildPasswordTF(),
if(widget.isLoading)
Column(
children: <Widget>[
SizedBox(height: 10.0),
CircularProgressIndicator(),
],
),
if(!widget.isLoading)
_buildLoginBtn(),
_buildSignUpWithText(),
_buildSocialBtnRow(),
_buildHomeChefSignUp(),
],),
),),
),],
),),
),);
}
}