How to do ElevatedButton disabled? - flutter

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.

Related

RenderBox was not laid out: flutter error

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.

Flutter Textformfield error message shifted down the next widget

I have an issue with my textformfield. Whenever the error message shows, it shifted down the next widget below...
I try to search how to give a placement for the error text to no take a placement that does not exist when it is not shown, but I didn't find the solution.
Here are the screenshot and the code of the issue.
class AuthForm extends StatefulWidget {
final bool isPassword;
final IconData prefixIcon;
final String hintText;
late bool isPasswordVisible = isPassword;
final bool isCalendar;
final TextEditingController controller;
final bool isDropDown;
final bool isPhone;
final String? Function(String?)? validator;
AuthForm({Key? key, this.isPassword = false, required this.prefixIcon, required this.hintText,
this.isCalendar = false, required this.controller, this.isDropDown = false, this.isPhone = false, required this.validator}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
#override
void initState() {
super.initState();
if (widget.isPhone){
getCountryCode();
}
}
start () async {
await CountryCodes.init();
}
Locale? getCountryCode () {
start();
final Locale? deviceLocale = CountryCodes.getDeviceLocale();
final CountryDetails details = CountryCodes.detailsForLocale();
return deviceLocale;
}
DateTime selectedDate = DateTime(2000,1);
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
#override
Widget build(BuildContext context) {
return widget.isDropDown ? const DropDownBar() :
SizedBox(
width: 70.w,
child: TextFormField(
validator: widget.validator,
keyboardType: widget.isPhone ? TextInputType.phone : TextInputType.text,
inputFormatters: [DialCodeFormatter()],
controller: widget.controller,
textAlign: TextAlign.center,
obscureText: widget.isPasswordVisible,
style: Theme.of(context).textTheme.bodyText2,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 2.3.h, 0, 0),
hintText : widget.hintText,
hintStyle: Theme.of(context).textTheme.bodyText1,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).splashColor,
width: 0.13.w,
),
),
errorStyle: Theme.of(context).textTheme.headline6,
prefixIcon: Container(
width: 0,
alignment: const Alignment(-0.99, 0.5),
child: Icon(
widget.prefixIcon,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
suffixIcon: Visibility(
visible: widget.isPassword,
//Maintain the space where the widget is even if it is hid
maintainAnimation: true,
maintainState: true,
maintainSize: true,
child: InkWell(
highlightColor : Colors.transparent,
splashColor: Colors.transparent,
child: Container(
width: 0,
alignment: const Alignment(0.99, 0.5),
child: Icon(
widget.isPasswordVisible ? Icons.visibility : Icons.visibility_off,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
onTap: () {
setState(() {
widget.isPasswordVisible = !widget.isPasswordVisible;
});
},
),
),
),
onTap: () async {
if (widget.isCalendar){
//Dismiss the keyboard
FocusScope.of(context).requestFocus(FocusNode());
//Call the calendar
await _selectDate(context);
widget.controller.text = DateFormat('dd-MM-yyyy').format(selectedDate);
}
}
),
);
}
}
Login Page
#override
Widget build(BuildContext context) {
return BlocListener<InternetCubit, InternetState>(
listener: (context, state) {
if (state is InternetDisconnected) {
showAlertBox(context);
}
},
child: Form(
key: _formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 6.h,
),
Text(
"Flexmes",
style: Theme.of(context).textTheme.headline1,
),
SizedBox(
height: 8.h,
),
AuthForm(
prefixIcon: Icons.email_outlined,
hintText: "Email",
controller: emailController,
nextFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Email is required'),
EmailValidator(errorText: 'Enter a valid email address'),
]),
),
SizedBox(
height: 3.h,
),
AuthForm(
isPassword: true,
prefixIcon: Icons.lock_rounded,
hintText: "Password",
controller: passwordController,
currentFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Password is required'),
MinLengthValidator(6, errorText: 'Password must be at least 6 digits long'),
PatternValidator(r'(?=.*?[#?!#$%^&*-])', errorText: 'Passwords must have at least one special character')
]),
),
SizedBox(
height: 4.5.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomCheckbox(
iconColor: Colors.black,
activeColor: const Color.fromARGB(255, 3, 218, 197),
),
SizedBox(
width: 3.w,
),
Text(
"Remember me",
style: Theme.of(context).textTheme.bodyText2,
)
],
),
),
SizedBox(
height: 4.5.h,
),
AuthButton(
text: "Log In",
onPressed: (){
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
if (_formkey.currentState!.validate()){
AuthenticationAPI(auth: FirebaseAuth.instance).signInWithEmail(emailController.text, passwordController.text);
//return navigation
}
}
}
),
SizedBox(
height: 3.2.h,
),
ClickableText(
text: "Forgot Password ?",
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
//return navigation
}
},
),
SizedBox(
height: 3.2.h,
),
const AuthDivider(
text: "OR",
),
SizedBox(
height: 2.h,
),
SizedBox(
width: 70.w,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableImage(
imagePath: "assets/images/icon/Facebook.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Instagram.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Tiktok.png",
width: 23.w,
onPressed: () {
null;
},
),
],
),
),
SizedBox(
height: 4.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account ? ",
style: Theme.of(context).textTheme.bodyText2,
),
ClickableText(
text: 'Sign up Now !',
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
Navigator.of(context).pushNamed("/signup1");
}
},
),
],
),
),
],
),
),
);
}
}
Thanks for your suggestion,
Chris
try wrapping textformfield with container and giving it height and width
Try wrapping TextFormField with container and give it height and width.

How to Dynamically change Icon Button to String or Emoji

So I am Making a Todo App, which has a work of Emoji in it.
I am Currently Using PubPackage, emoji_picker: ^0.1.0 For its help i can open and Close Emoji Keyboard Easily.
BTW, the Code You can see, is a Code of Opening EmojiKeyboard.
Widget emojiSelect() {
return EmojiPicker(
numRecommended: 25,
recommendKeywords: ["sing", "coding"],
columns: 7,
rows: 3,
onEmojiSelected: (emoji, catergory) {
print(emoji);
});
}
Here, when I am Pressing the button, A Emoji Keyboard is Opening Perfectly,
And I am pretty happy with it.
Now, I want to Make something, like if we Click on one of the Emoji which is resting inside the Emoji_keyboard then the Icon as you can see(in the below image)
Changes to Emoji, which User Clicked through KeyBoard.
Is there a Way, the Icon to change itself to "Emoji" that the user Clicked and if we long-press the same Button we can again Edit the Emoji to choose another, as per our choice?
The Whole Code, Pretty much looks like this,
return Wrap(
children: [
WillPopScope(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Wrap(
//height: MediaQuery.of(context).size.height / 4.8,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
TextFormField(
focusNode: focusNode,
autofocus: false,
autocorrect: true,
decoration: InputDecoration(
hoverColor: Colors.amber,
border: InputBorder.none,
prefixIcon: Icon(CarbonIcons.pen_fountain),
hintText: "What toodo?",
hintStyle: TextStyle(
color: Colors.black54,
fontWeight: FontWeight.w200),
contentPadding: EdgeInsets.all(20.0),
),
),
// TextFormField(
// autocorrect: true,
// decoration: InputDecoration(
// hoverColor: Colors.amber,
// border: InputBorder.none,
// prefixIcon: Icon(CarbonIcons.pen),
// hintText: "Description (optional)",
// hintStyle: TextStyle(
// color: Colors.black54,
// fontWeight: FontWeight.w200),
// contentPadding: EdgeInsets.all(20.0),
// ),
// ),
Row(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: Icon(CarbonIcons.notification),
onPressed: () async {
final TimeOfDay newTime =
await showTimePicker(
context: context,
initialTime:
TimeOfDay(hour: 7, minute: 15),
);
},
color: Colors.black54,
),
IconButton(
icon: Icon(CarbonIcons.face_add),
onPressed: () {
setState(() {
focusNode.unfocus();
focusNode.canRequestFocus = false;
showEmojiKeyboard = !showEmojiKeyboard;
});
},
color: Colors.black54,
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FlatButton.icon(
onPressed: () {},
color: Colors.blue,
icon: Icon(
CarbonIcons.add,
color: Colors.white,
),
label: Text(
"Add Todo",
style: TextStyle(color: Colors.white),
))
],
),
Divider(),
],
)
],
),
],
),
showEmojiKeyboard ? emojiSelect() : Container(),
],
),
onWillPop: () {
if (showEmojiKeyboard) {
setState(() {
showEmojiKeyboard = false;
});
} else {
Navigator.pop(context);
}
return Future.value(false);
},
),
],
);
Seems like the selected emoji type is String so basically on selection of emoji you need to display a Text Widget in place of the icon.
String selectedEmoji;
Widget emojiSelect() {
return EmojiPicker(
numRecommended: 25,
recommendKeywords: ["sing", "coding"],
columns: 7,
rows: 3,
onEmojiSelected: (emoji, catergory) {
setState((){
selectedEmoji = emoji;
})
});
}
And the place where you show the icon has to be replaced with the Text() widget conditionally
IconButton(
icon: selectedEmoji==null? Icon(CarbonIcons.face_add):Text(selectedEmoji),
onPressed: () {
setState(() {
focusNode.unfocus();
focusNode.canRequestFocus = false;
showEmojiKeyboard = !showEmojiKeyboard;
});
},
color: Colors.black54,
)

Flutter : How to do this kind of UI in Flutter to select dates

Hello Friends,
Can someone guide me to do this kind of UI making in flutter?
Thanks in advance...
I hope this code will work for you. You just need to add your datepicker logic on this textfield.
body: Container(
child: Row(
children: [
Container(
width: 5,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Start Date"),
GestureDetector(
onTap: () {
selectDate(context);
},
child: AbsorbPointer(
absorbing: true,
child: TextFormField(
style: TextStyle(color: Colors.black),
controller: startdata,
decoration: InputDecoration(
suffixIcon:
Icon(Icons.calendar_today, color: Colors.blue)),
),
),
)
],
)),
Container(
width: 5,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("End Date"),
GestureDetector(
onTap: () {
// Your second date picker logic
},
child: AbsorbPointer(
absorbing: true,
child: TextFormField(
controller: enddata,
decoration: InputDecoration(
suffixIcon:
Icon(Icons.calendar_today, color: Colors.blue)),
),
),
)
],
)),
Container(
width: 5,
),
],
)),
Select Date
TextEditingController startdata = new TextEditingController();
TextEditingController enddata = new TextEditingController();
DateTime selectedDate = DateTime.now();
var myFormat = DateFormat('yyyy-MM-dd');
Future selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: selectedDate,
lastDate: DateTime(2101),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
primaryColor: WidgetColors.buttonColor,
accentColor: WidgetColors.buttonColor,
colorScheme: ColorScheme.light(primary: WidgetColors.buttonColor),
buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
),
child: child,
);
},
);
if (picked != null) {
setState(() {
selectedDate = picked;
startdata = TextEditingController(text: myFormat.format(picked),);
});
} else {}
}
Try this
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Start Date", style: TextStyle(
color: Colors.blueGrey,
),),
SizedBox(height: 15.0,),
GestureDetector(
onTap: () {
// Show You Date Picker Here
},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("YourDate e.g May 7, 2018"),
Icon(Icons.calendar_today, color: Colors.blue,),
],
),
),
)
],
),
),
SizedBox(width: 10.0,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("End Date", style: TextStyle(
color: Colors.blueGrey,
),),
SizedBox(height: 15.0,),
GestureDetector(
onTap: () {
// Show You Date Picker Here
},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("YourDate e.g May 8, 2018"),
Icon(Icons.calendar_today, color: Colors.blue,),
],
),
),
),
],
),
),
],
)
I have a generic TextFieldWidget class I use for all my Flutter projects, which is really useful and can answer your question.
enum TextFieldType {
Password,
Email,
Text,
Picker,
}
class TextFieldWidget extends StatefulWidget {
final TextEditingController controller;
final FocusNode focusNode;
final Key key;
final String errorText;
final String hintText;
final Color errorBorderColor;
final bool autofocus;
final bool isEnabled;
final Function onChanged;
final Function onTap;
final TextFieldType textFieldType;
final TextCapitalization textCapitalization;
final Widget suffixIcon;
TextFieldWidget({
this.controller,
this.focusNode,
this.key,
this.errorText,
this.hintText,
this.errorBorderColor,
this.autofocus = false,
this.isEnabled = true,
this.onChanged,
this.onTap,
this.textFieldType = TextFieldType.Text,
this.textCapitalization = TextCapitalization.none,
this.suffixIcon,
});
#override
State createState() => _TextFieldWidgetState();
}
class _TextFieldWidgetState extends State<TextFieldWidget> {
final double _borderSideWidth = 0.5;
bool _shouldObscureText = true;
#override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: !widget.isEnabled ? ThemeColors.text.tertiaryLight : null,
fontSize: ThemeFonts.size.textFieldText,
),
enabled: widget.isEnabled,
controller: this.widget.controller,
focusNode: this.widget.focusNode,
decoration: _getTextFieldDecoration(),
autofocus: this.widget.autofocus,
obscureText: _shouldTextBeObscured(),
onChanged: this.widget.onChanged,
onTap: this.widget.onTap,
keyboardType: _getKeyboardType(),
textCapitalization: this.widget.textCapitalization,
enableInteractiveSelection: this.widget.textFieldType != TextFieldType.Picker,
);
}
InputDecoration _getTextFieldDecoration() {
return InputDecoration(
suffixIcon: _getSuffixIcon(),
labelText: widget.hintText,
labelStyle: TextStyle(color: ThemeColors.text.tertiary),
errorText: widget.errorText,
errorStyle: TextStyle(
color: widget.isEnabled ? ThemeColors.text.tertiary : ThemeColors.text.tertiaryLight,
fontSize: ThemeFonts.size.textFieldPlaceholder,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.border.secondary,
width: _borderSideWidth,
),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: this.widget.errorBorderColor ?? ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
);
}
TextInputType _getKeyboardType() {
switch (this.widget.textFieldType) {
case TextFieldType.Email:
return TextInputType.emailAddress;
default:
return TextInputType.text;
}
}
Widget _getSuffixIcon() {
switch (this.widget.textFieldType) {
case TextFieldType.Picker:
return Icon(Icons.unfold_more);
case TextFieldType.Password:
return IconButton(
icon: Icon(Icons.remove_red_eye),
color: _shouldObscureText ? ThemeColors.icon.secondaryLight : ThemeColors.icon.secondary,
onPressed: () {
setState(() {
_shouldObscureText = !_shouldObscureText;
});
},
);
case TextFieldType.Text:
return this.widget.suffixIcon != null ? this.widget.suffixIcon : null;
default:
return null;
}
}
bool _shouldTextBeObscured() {
if (widget.textFieldType == TextFieldType.Password) {
return _shouldObscureText;
}
return false;
}
}
And when you want to use it for Date picking just call it like this:
TextFieldWidget(
focusNode: _dateFocusNode,
controller: _dateTextController,
textFieldType: TextFieldType.Picker,
hintText: 'Date of birth',
onTap: () {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).requestFocus(FocusNode());
}
// Call code that opens date picker here
},
),
Keep in mind this TextField provides more options than what you need right now, but if you plan on having error handling, different UI colours for those cases, different UI for password, email and other input this will be of great help.

TextFormField losing value when changing focus

I am trying to move to other TextFormField but whenever I lose focus from first TextFormField text became empty, I search about this issue but I don't find any solution till now.
var _formKey = GlobalKey<FormState>();
Note note;
TextEditingController titleController=TextEditingController();
TextEditingController descriptionController=TextEditingController();
#override
Widget build(BuildContext context) {
TextStyle textStyle=Theme.of(context).textTheme.title;
titleController.text=note.title;
descriptionController.text=note.description;
// TODO: implement build
return WillPopScope(
onWillPop: (){
moveToLastScreen();
},
child:Scaffold(
appBar: AppBar(
title: Text("appBarTitle"),
leading: IconButton(icon:Icon(Icons.arrow_back),onPressed: (){
moveToLastScreen();
},),
),
body: Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.only(top: 15.0,left: 15.0,right: 10.0),
child: ListView(
children: <Widget>[
//1st element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0,),
child: TextFormField(
validator: (String value){
if(value.isEmpty)
{
return "Please enter Title";
}
},
controller: titleController,
style: textStyle,
onSaved: (value){
debugPrint("Something changed in title Text field");
updateTitle();
},
/*onChanged: (value){
debugPrint("Something changed in title Text field");
updateTitle();
},*/
decoration: InputDecoration(
labelText: "Title",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)
)
),
),
),
//2nd element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0,),
child: TextFormField(
validator: (String value){ //2nd step for form with validation
if(value.isEmpty)
{
return "Please enter principle amount";
}
},
onSaved: (value){
debugPrint("Something changed in Description Text field");
updateDescription();
},
controller: descriptionController,
style: textStyle,
/*onChanged: (value){
debugPrint("Something changed in Description Text field");
updateDescription();
},*/
decoration: InputDecoration(
labelText: "Description",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0)
)
),
),
),
//3th element
Padding(
padding: EdgeInsets.only(top: 15.0,bottom: 15.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
color: Theme.of(context).primaryColorDark,
textColor: Theme.of(context).primaryColorLight,
child: Text("Save",textScaleFactor: 1.5,),
onPressed: (){
setState(() {
if(_formKey.currentState.validate()) {
debugPrint("Save Pressed");
_save();
}
});
}
),
),
Container(width: 5.0,),
Expanded(
child: RaisedButton(
color: Theme.of(context).primaryColorDark,
textColor: Theme.of(context).primaryColorLight,
child: Text("Delete",textScaleFactor: 1.5,),
onPressed: (){
setState(() {
debugPrint("Delete Pressed");
_delete();
});
}
),
),
],
),
),
],
),
)),
));
}
Please suggest me I am new in flutter.
Remove titleController.text=note.title; descriptionController.text=note.description; from your build method and place it in initState method.
You will lose the value in the textField because those lines get executed anytime there is a rebuild, thereby replacing the values gotten from the textFields and replacing it with note.title and note.description which are empty at that point.
In other words, remove those lines and add this to your code.
#override
void initState() {
super.initState();
titleController.text=note.title;
descriptionController.text=note.description;
}