how to create a textfield with centered hint text and suffix icon?
i make centered hint with TextAlign.center
the problem is that when i add an suffix icon hint does not stay in center and moves to left
Well, this is working fine for me.
If it doesn't work, maybe is something else affecting your UI.
Please try this snippet.
TextField(
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: 'Center the text',
suffixIcon: IconButton(
icon: Icon(Icons.add),
onPressed: () {
debugPrint('click bait');
}
),
),
),
Try with a below code snippet that has prefix and sufixicon in a textformField
Create a Textfield widget like a below:
import 'package:flutter/material.dart';
import 'package:row_nation/Utils/app_colors.dart';
import 'package:row_nation/Utils/app_font_size.dart';
import 'package:row_nation/Utils/app_font_weight.dart';
class PassWordTextFormFieldWidget extends StatelessWidget {
final TextEditingController controllerName;
final String hintTxt;
final TextInputType keyboardType;
final Color cursorColor;
final Function(String) onChange;
final Function(String) onSaved;
final String? Function(String?)? validatorData;
final IconData prefixIcon;
final IconData suffixIcon;
final Function() sufficIconTap;
PassWordTextFormFieldWidget({
super.key,
required this.controllerName,
required this.hintTxt,
required this.prefixIcon,
required this.keyboardType,
required this.cursorColor,
required this.onChange,
required this.onSaved,
required this.validatorData,
required this.suffixIcon,
required this.sufficIconTap,
});
#override
Widget build(BuildContext context) {
double? height, width;
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColors.kEmptyDotColor.withOpacity(0.4),
),
child: TextFormField(
controller: controllerName,
cursorColor: cursorColor,
obscureText: true,
textAlign: TextAlign.left,
keyboardType: keyboardType,
style: Theme.of(context).textTheme.caption?.copyWith(
color: AppColors.kWhiteColor,
letterSpacing: 0.2,
fontSize: AppFontSize.fourteenFontSize,
fontWeight: AppFontWeight.sixHundredFont,
),
validator: (value) {
// widget.validatorData!(value);
return validatorData!(value);
},
onChanged: (va) {
onChange(va);
},
onSaved: (val) {
print(val);
},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
horizontal: 15,
vertical: 15,
),
isDense: true,
hintText: hintTxt,
hintStyle: Theme.of(context).textTheme.caption?.copyWith(
color: AppColors.kIconColor,
fontSize: AppFontSize.twelveFontSize,
fontWeight: AppFontWeight.fourHundredFont,
),
// When user gets Error
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: AppColors.kRedColor,
),
),
// When user getting error and focuses on a textformfield
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: AppColors.kRedColor,
),
),
// When user Focuses on textformField widget
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: AppColors.kSplashBackColor,
),
),
// Default TextformField Color
enabledBorder: InputBorder.none,
suffixIcon: GestureDetector(
onTap: () {
sufficIconTap();
},
child: Icon(
suffixIcon,
size: 15,
color: AppColors.kIconColor,
),
),
prefixIcon: Icon(
prefixIcon,
size: 15,
color: AppColors.kIconColor,
),
// border: InputBorder.none,
),
),
);
}
}
and use it wherever like a below :
PassWordTextFormFieldWidget(
controllerName: passwordController,
prefixIcon: Icons.lock,
suffixIcon: Icons.visibility_off,
sufficIconTap: () {
print("Visibility Icon Tapped");
},
hintTxt: AppStrings.passwordTxt,
keyboardType: TextInputType.text,
cursorColor: AppColors.kSplashBackColor,
onChange: (p0) {},
onSaved: (p0) {},
validatorData: (p0) {},
),
Don't forget to upvote if found useful.
Related
I'm working on a CustomFormField class to customize the default behaviour of the TextFormField. One of the things I wanted to do was move the position of the errorText to prevent it from adjusting the position of other fields on the form in the event of an error. I have achieved half of my goal by using a stack and repositioning the errorText to appear on the lower border of the field instead of a several pixels below. Unfortunately the default behaviour still reserves the space and the other fields move anyway.
Text Fields without error condition
Text Fields with error condition
As you can see the errorText is no longer taking up space but the default behaviour of the TextFormField takes the space anyway.
Is there a way to prevent this?
It's a little long and this is still a work in progress but here is the code I'm using.
class CustomFormField extends StatefulWidget {
final GlobalKey formKey;
final TextEditingController controller;
final FocusNode currentFocusNode;
final FocusNode futureFocusNode;
final TextInputType inputType;
final TextInputAction inputAction;
final bool allowShowPassword;
final bool enabled;
final bool autoFocus;
final String labelText;
final String hintText;
final FormFieldValidator<String>? validator;
final Function? onChanged;
final FormFieldSetter<String>? onSaved;
const CustomFormField(
{super.key,
required this.formKey,
required this.controller,
required this.currentFocusNode,
required this.futureFocusNode,
this.inputType = TextInputType.text,
this.inputAction = TextInputAction.next,
this.allowShowPassword = true,
this.enabled = true,
this.autoFocus = false,
this.labelText = '',
this.hintText = '',
this.validator,
this.onChanged,
this.onSaved});
#override
State<CustomFormField> createState() => _CustomFormFieldState();
}
class _CustomFormFieldState extends State<CustomFormField> {
bool _passwordHidden = true;
bool onError = false;
String _errorText = '';
#override
Widget build(BuildContext context) {
// grab the application theme to use when colouring text fields
ThemeData theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Stack(
children: [
TextFormField(
enabled: widget.enabled,
autofocus: widget.autoFocus,
textInputAction: widget.inputAction,
onEditingComplete: () =>
FocusScope.of(context).requestFocus(widget.futureFocusNode),
focusNode: widget.currentFocusNode,
keyboardType: widget.inputType,
obscureText: (widget.inputType == TextInputType.visiblePassword &&
_passwordHidden)
? _passwordHidden
: false,
controller: widget.controller,
validator: (value) {
String? errorText = widget.validator!.call(value);
if (errorText != null && Static.formIsValid) {
Static.formIsValid = false;
widget.currentFocusNode.requestFocus();
setState(() {
onError = true;
_errorText = errorText;
});
} else {
setState(() {
onError = false;
_errorText = '';
});
}
// the validator still needs us to return null if there was no error
// but if there is an error return empty string
return errorText == null ? null : '';
},
onSaved: widget.onSaved,
onChanged: (value) {
if (widget.onChanged != null) {
widget.onChanged!.call(value);
}
},
style: TextStyle(
color: widget.enabled
? Constants.formFieldColor
: theme.disabledColor,
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Ariel'),
decoration: InputDecoration(
labelText: widget.labelText,
hintText: widget.hintText,
hintStyle: const TextStyle(color: Colors.white38),
contentPadding: const EdgeInsets.symmetric(horizontal: 25),
// constraints: const BoxConstraints(maxHeight: 40, minHeight: 40),
filled: true,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
errorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.red)),
focusedErrorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
disabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
alignLabelWithHint: true,
focusColor: Colors.black,
suffixIcon: widget.inputType == TextInputType.visiblePassword &&
widget.allowShowPassword
? InkWell(
onTap: () {
setState(() {
_passwordHidden = !_passwordHidden;
});
},
child: Icon(
_passwordHidden
? Icons.visibility_off_outlined
: Icons.visibility_outlined,
color: Constants.passwordShowHideIconColor,
size: 18,
),
)
: null,
),
),
// this repositions the errorText to appear just on top of the lower border
onError
? Positioned(
bottom: 17,
left: 25,
child: Container(
height: 15,
decoration: const BoxDecoration(color: Colors.white),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Text(_errorText,
style: const TextStyle(
color: Colors.red,
fontSize: 13,
fontStyle: FontStyle.normal)),
),
),
)
: Container(),
],
),
);
}
}
One thing I did try was wrapping it all in a SizedBox. This did stop other fields from changing their positions but it had the side affect of shrinking the size of the field with the error because it always wants that space for the errorText.
Any help would be appreciated.
Solved:
I was able to solve this by adding:
errorStyle: const TextStyle(height: 0),
This stopped the field from taking additional space for the error text.
My idea is to use only one TextFormField for the email and password...
But I also want to make the password obscure, and I have no idea how to implement this, using just a TextFormField
TextFormField inputField({
required String hintText,
required String errorMessage,
required bool isPassword,
}) {
return TextFormField(
decoration: InputDecoration(
enabledBorder: inputBorder(const Color(0xFF000000), 2),
focusedBorder: inputBorder(const Color(0xFF000000), 3),
errorBorder: inputBorder(const Color(0xFFF44336), 2),
focusedErrorBorder: inputBorder(const Color(0xFFF44336), 3),
hintText: hintText,
hintStyle: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return errorMessage;
}
return null;
},
obscureText: isPassword,
);
}
Padding password:
Padding(
padding: const EdgeInsets.only(top: 24, left: 32, right: 24),
child: Stack(
children: [
SizedBox(
height: 60,
child: Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 16),
child: GestureDetector(
onTap: () {_changeIcon(passwordIcon);},
child: passwordIcon,
),
),
),
),
inputField(
hintText: 'password',
errorMessage: 'Please enter your password',
isPassword: _LoginFormState()._isHidden,
),
],
),
),
Is there any way to implement this? Sorry for anything I just started on Flutter :(
Here is a example:
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late TextEditingController _emailEditingController;
late TextEditingController _passwordEditingController;
#override
Widget build(BuildContext context) {
return Column(children: [
inputField(
hintText: 'email',
errorMessage: 'errorMessage',
isPassword: false,
textEditingController: _emailEditingController),
inputField(
hintText: 'password',
errorMessage: 'errorMessage',
isPassword: true,
textEditingController: _passwordEditingController),
]);
}
#override
void dispose() {
_emailEditingController.dispose();
_passwordEditingController.dispose();
super.dispose();
}
}
And your helper method:
TextFormField inputField(
{required String hintText,
required String errorMessage,
required bool isPassword,
required TextEditingController textEditingController}) {
return TextFormField(
decoration: InputDecoration(
enabledBorder: inputBorder(const Color(0xFF000000), 2),
focusedBorder: inputBorder(const Color(0xFF000000), 3),
errorBorder: inputBorder(const Color(0xFFF44336), 2),
focusedErrorBorder: inputBorder(const Color(0xFFF44336), 3),
hintText: hintText,
hintStyle: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
controller: textEditingController,
validator: (value) {
if (value == null || value.isEmpty) {
return errorMessage;
}
return null;
},
obscureText: isPassword,
);
}
Here you are using TextEditingController to re use these method, if you want more info about it: TextEditingController
Whenever the user modifies a text field with an associated TextEditingController, the text field updates value and the controller notifies its listeners.
add this line your code keyboardType: isPassword ? TextInputType.text : TextInputType.emailAddress,
TextFormField(
decoration: InputDecoration(
enabledBorder: inputBorder(const Color(0xFF000000), 2),
focusedBorder: inputBorder(const Color(0xFF000000), 3),
errorBorder: inputBorder(const Color(0xFFF44336), 2),
focusedErrorBorder: inputBorder(const Color(0xFFF44336), 3),
hintText: hintText,
hintStyle: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return errorMessage;
}
return null;
},
keyboardType: isPassword ? TextInputType.text : TextInputType.emailAddress,
obscureText: isPassword,
)
i have created multiple text field using a single method in different file how i retrieve the value from them. I want to retrieve the value in different variables.
//class method
class CustomTextField {
static TextField display(BuildContext context, [String name, double size=16,IconData icon]) {
return new TextField(
textAlign: TextAlign.center,
style: CustomTextStyle.display(context, Colors.black38, size),
decoration: new InputDecoration(
alignLabelWithHint: true,
icon: new Icon(icon),
contentPadding:EdgeInsets.only(top: 30,right: 30,),
border: InputBorder.none,
hintText:"$name",
focusedBorder: InputBorder.none,
hintStyle: CustomTextStyle.display(context, Colors.grey, size),
),
);
}
}
//call method
new Container(
width: width,
height: height,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(Radius.circular(20)),
gradient: new LinearGradient(
colors: [
Color.fromRGBO(252, 191, 93, 1),
Color.fromRGBO(255, 210, 119, 1),
Color.fromRGBO(252, 215, 85, 1),
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
),
child: CustomTextField.display(context, name,16,icon),
),
First of all, I recommend that you use Stateless Widget to create your TextField instead of using a static function like this code below:
class CustomTextField extends StatelessWidget {
final Function(String) onChanged;
final String name;
final double size;
final IconData icon;
CustomTextField({
this.onChanged,
this.name,
this.size: 16,
this.icon,
});
Widget build(BuildContext context) {
return new TextField(
textAlign: TextAlign.center,
onChanged: onChanged,
style: CustomTextStyle.display(context, Colors.black38, size),
decoration: new InputDecoration(
alignLabelWithHint: true,
icon: new Icon(icon),
contentPadding: EdgeInsets.only(
top: 30,
right: 30,
),
border: InputBorder.none,
hintText: "$name",
focusedBorder: InputBorder.none,
hintStyle: CustomTextStyle.display(context, Colors.grey, size),
),
);
}
}
Then, create a function for the onChange field to receive the new value:
class App extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: width,
height: height,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(Radius.circular(20)),
gradient: new LinearGradient(
colors: [
Color.fromRGBO(252, 191, 93, 1),
Color.fromRGBO(255, 210, 119, 1),
Color.fromRGBO(252, 215, 85, 1),
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
),
child: CustomTextField(
// Here you get the value change
onChanged: (value) {
print('Text value changed');
print('New value: $value');
},
name: name,
size: 16,
icon: icon,
),
),
);
}
}
Use Function as a parameter for your CustomTextField and add it to onChanged parameter of TextField;
class CustomTextField {
static TextField display(BuildContext context, Function onChanged,
[String name, double size = 16, IconData icon]) {
return new TextField(
textAlign: TextAlign.center,
onChanged: onChanged,
style: CustomTextStyle.display(context, Colors.black38, size),
decoration: new InputDecoration(
alignLabelWithHint: true,
icon: new Icon(icon),
contentPadding: EdgeInsets.only(
top: 30,
right: 30,
),
border: InputBorder.none,
hintText: "$name",
focusedBorder: InputBorder.none,
hintStyle: CustomTextStyle.display(context, Colors.grey, size),
),
);
}
}
then get your value;
CustomTextField.display(
context,
(value) {
print(value);
},
name,
16,
icon,
),
you should provide a function to handle the onChange property of your custom text field.
here is how i used one in a project of mine:
the custom class widget
class MyTextField extends StatefulWidget {
final String title;
final Function onChange; // you can get the value from this function
final bool isPassword;
MyTextField(this.title, this.onChange, {this.isPassword = false});
#override
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
bool showPassword = false;
final _controller = TextEditingController();
#override
Widget build(BuildContext context) {
_controller.addListener(() {
setState(() {});
});
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
SizedBox(height: 2),
TextField(
controller: _controller,
onChanged: widget.onChange,
obscureText: !showPassword && widget.isPassword,
decoration: InputDecoration(
suffixIcon: widget.isPassword
? IconButton(
icon: Icon(
Icons.remove_red_eye,
color: showPassword ? Colors.blue : Colors.grey,
),
onPressed: () {
setState(() => showPassword = !showPassword);
},
)
: IconButton(
icon: Icon(
Icons.clear,
color: _controller.text.isEmpty
? Colors.grey
: Colors.blue,
),
onPressed: () => _controller.clear()),
border: InputBorder.none,
fillColor: Color(0xfff3f3f4),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 5.0),
),
filled: true),
)
],
),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}
the use case:
MyTextField('Email', (value) => email = value.trim()), // body of onChange
MyTextField(
'Password',
(value) => password = value.trim(), // body of onChange
isPassword: true,
),
// value is what you get from the text fields.
Provide a TextEditingController as a parameter to construct your CustomTextField.
I want to change the color of the text when the user enters something. But when only if the user enter something. Otherwise, it should remain the same that is grey. For this, I am creating a Focus Node inside the component and assigning it to the textformfield focusNode property. In initState I am adding a listener so whenever my textformfield has focus I can change the color of the hint text as well as the border color. But it is giving me an error and I am not able the change the color of the user enter text.
FocusNode _focusNode = FocusNode();
#override
void initState() {
_focusNode.addListener(() {
setState(() => color = _focusNode.hasFocus ? Colors.blue : Colors.grey);
});
super.initState();
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
And my component is like this below :
return Container(
height: MediaQuery.of(context).size.height * 0.06,
child: Material(
elevation: 5.0,
borderRadius: BorderRadius.all(
Radius.circular(30.0),
),
child: TextFormField(
controller: textController,
focusNode: _focusNode,
onTap: _requestFocus,
keyboardType: this.widget.type,
textAlignVertical: TextAlignVertical.bottom,
onChanged: (value) => {
setState(() {
_color = Colors.blue;
})
},
style: TextStyle(
color: color,
fontWeight: FontWeight.w400,
fontSize: 15.0,
),
obscureText: widget.obscureText,
decoration: InputDecoration(
filled: true,
fillColor: Color(0xFFFCFCFC),
hintText: this.widget.hintText,
isDense: true,
contentPadding: EdgeInsets.all(40.0),
hintStyle: TextStyle(
color: _focusNode.hasFocus ? Colors.blue : Colors.grey,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
borderSide: const BorderSide(color: Colors.white, width: 0.0),
),
prefixIcon: Icon(
this.widget.icon,
color: Colors.grey,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(50.0)),
borderSide: BorderSide(
color: Colors.blue,
),
),
),
validator: (String value) {
return;
},
),
),
);
I am not able to determine what I am doing wrong.
Edit: I have move the initialization of the focus node in initSate and in onChanged property i am setting the color to grey within setState. but still giving error Failed assertion: line 742 pos 12: 'attached': is not true.
I solved the issue by doing these changes :
void _requestFocus() {
setState(() {
FocusScope.of(context).unfocus();
FocusScope.of(context).requestFocus(_focusNode);
});
}
removing onChanged call back and giving the color blue to the textfield.
Thats it.
I'm working on a TextFormField to accept passwords. I have set the suffix icon to have IconButton child to detect on click events and to toggle the obscuretext attribute of the TextFormField. The callback function for the iconButton gets called but the TextFormField doesn't get repainted. Any ideas on how to solve this?
static Widget buildTextFormField(String id,
FormFieldValidator<String> validateField,
FormFieldSetter<String> saveField,
InputDecoration decoration,
EdgeInsetsGeometry paddingInfo,
EdgeInsetsGeometry marginInfo,
TextInputType keyboardType,
{bool obscureField:false, double width:328.0,
TextEditingController controller}
){
return Container(
padding: paddingInfo,
margin: marginInfo,
width: width,
child: TextFormField(
key: Key(id),
obscureText: obscureField,
validator: validateField,
onSaved: saveField,
keyboardType: keyboardType,
decoration: decoration,
controller: controller,
),
);
}
InputDecoration passwordDecoration = InputDecoration(
hintText: 'Password',
labelText: 'Enter your password',
suffixIcon:
IconButton(
icon: Icon(
_passwordVisible ? Icons.visibility : Icons.visibility_off,
semanticLabel: _passwordVisible ? 'hide password' : 'show password',
),
onPressed: () {
setState(() {
_passwordVisible ^= true;
//print("Icon button pressed! state: $_passwordVisible"); //Confirmed that the _passwordVisible is toggled each time the button is pressed.
});
}),
labelStyle: TextStyle(
fontFamily: 'Roboto Medium',
fontSize: 12.0,
color: Color(0x99000000),
letterSpacing: 0.4,
),
);
final passwordPaddingInfo = const EdgeInsets.only(top: 15.0, bottom:15.0,
left: 22.0, right:25.0);
this._passwordField = AdministrationComponents.
buildTextFormField('passwordField', validatePassword,
(value) => _password = value, passwordDecoration, passwordPaddingInfo,
null, null, controller:_passwordController,
obscureField: !_passwordVisible);
Try to this
bool _showPassword = false;
void _togglevisibility() {
setState(() {
_showPassword = !_showPassword;
});
}
Textform field code
child: TextFormField(
controller: _passwordController,
obscureText: !_showPassword,
cursorColor: Colors.red,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Password",
border: InputBorder.none,
suffixIcon: GestureDetector(
onTap: () {
_togglevisibility();
},
child: Icon(
_showPassword ? Icons.visibility : Icons
.visibility_off, color: Colors.red,),
),
),
),
Show/Hide Passwords in Flutter's TextFormField
Step 1:
bool _obscureText = true;
Step 2:
void _toggle() {
setState(() {
_obscureText = !_obscureText;
});
}
Step 3:
TextField(
controller: password,
style: TextStyle(fontSize: 16.0),
obscureText: _obscureText,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
hintText: "Password",
suffixIcon: InkWell(
onTap: _toggle,
child: Icon(
_obscureText
? FontAwesomeIcons.eye
: FontAwesomeIcons.eyeSlash,
size: 15.0,
color: Colors.black,
),
),
),
),
Thanks #ShyjuM and # diegoveloper! I see what I was doing wrong - I was calling the buildTextFormField in the constructor of my State class and not in the build method. Moving the call to buildTextFormField inside the build method fixed it. Thanks again for all of your help!
You have some errors in your code.
Replace this :
_passwordVisible > Icons.visibility : Icons.visibility_off,
and
_passwordVisible ^= true;
By this:
_passwordVisible ? Icons.visibility : Icons.visibility_off,
and
_passwordVisible = !_passwordVisible;
This is the Password dart i use
import 'package:flutter/material.dart';
class LoginPass extends StatefulWidget {
LoginPass(this.controllerUpass);
final Function controllerUpass;
#override
_LoginPassState createState() => _LoginPassState();
}
class _LoginPassState extends State<LoginPass> {
bool _isHidden = true;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(0, 30, 0, 10),
child: Container(
height: 35,
child: Center(
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: TextField(
obscureText: _isHidden,
onChanged: (value) {
widget.controllerUpass(value);
},
decoration: InputDecoration(
hintText: 'Password',
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
suffixIcon: GestureDetector(
onTap: () {
setState(() {
_isHidden = !_isHidden;
});
},
child: _isHidden
? Icon(
Icons.remove_red_eye_sharp,
color: Colors.blue,
)
: Icon(
Icons.remove_red_eye,
color: Colors.red,
),
)),
),
),
),
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black26,
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 3),
),
],
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(3)),
),
),
);
}
}
In Main call
LoginPass(controllerUpass),