Toggle password visibility using Gesture Detector - flutter

I'm new to flutter and following a tutorial where using an icon, the visibility of a password changes from hidden to visible.
I saw some cases where IconButton is used but even though I tried that method I'm still getting red lines everywhere. I wish to know where exactly the problem is unless it's a version related issue.
the variables are defined as such:
late String _password, _email;
bool _isObscure = true;
The Form Field
Widget _showPasswordInput() {
return TextFormField(
onSaved: (val) => _password = val!,
obscureText: _isObscure,
decoration: const InputDecoration(
// border: OutlineInputBorder(),
suffixIcon: GestureDetector(
onTap: () {
setState(() {
_isObscure = !_isObscure;
});
},
child: Icon(
_isObscure ? Icons.visibility : Icons.visibility_off,
),
),
labelText: 'Password',
hintText: 'Enter valid password, min: 6 chars',
icon: Icon(Icons.lock),
),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter some text';
}
return null;
},
);
}
How it's used in the build
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
_showRegisterButton(),
]))),
)),
);
}

Inside InputDecoration, data is changing on runtime, therefore it cannot be const
decoration: InputDecoration(
// border: OutlineInputBorder(),
suffixIcon: GestureDetector(
onTap: () {
setState(() {
_isObscure = !_isObscure;
});
},
child: Icon(
_isObscure ? Icons.visibility : Icons.visibility_off,
),
),
and create a method like myTextFiled(BuildContext context) => TextFormField(....)

Related

Form validator is not showing error in flutter why?

I created form when i click on button to validate validator not showing error.
GlobalKey<FormState> formkey= GlobalKey<FormState>();
Created Global Key in my code
Form(
key: formkey,
child: ListView(
scrollDirection: Axis.vertical,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: TextFormField(
controller: _name,
validator: (value) {
if (value == null || value == value.isEmpty) {
return "Enter Name";
}
return null;
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(),
labelText: "Name",
prefixIcon: Icon(Icons.person),
errorStyle: TextStyle(color: Colors.red)),
),
),
I created form
Center(
child: ElevatedButton(
onPressed: () {
if (formkey.currentState!.validate()) {
setState(() {
name = _name.text;
email = _email.text;
password = _password.text;
});
addUser();
clear();
}
},
child: Text("Register"))),
Code of button
This is the code help me.
remove value == from the condition it will work.
write like this
if (value == null || value.isEmpty)
I solved your answer like this:
import 'package:flutter/material.dart';
class MyStackAns extends StatefulWidget {
const MyStackAns({super.key});
#override
State<MyStackAns> createState() => _MyStackAnsState();
}
class _MyStackAnsState extends State<MyStackAns> {
GlobalKey<FormState> formkey = GlobalKey<FormState>();
final TextEditingController _name = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stack Answers'),
),
body: Column(
children: [
Form(
key: formkey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Padding(
padding: const EdgeInsets.all(20),
child: TextFormField(
controller: _name,
validator: (value) {
if (value == null || value.isEmpty) {
return "Enter Name";
}
return null;
},
decoration: const InputDecoration(
enabledBorder: OutlineInputBorder(), focusedBorder: OutlineInputBorder(), labelText: "Name", prefixIcon: Icon(Icons.person), errorStyle: TextStyle(color: Colors.red)),
),
),
),
Center(
child: ElevatedButton(
onPressed: () {
if (formkey.currentState!.validate()) {
//Perform your validate task here
}
},
child: const Text("Register"))),
],
),
);
}
}

I do all possible to solve that error Null check operator used on a null value I use (!) but there is error

class login extends StatelessWidget {
var emailController = TextEditingController();
var PasswordController = TextEditingController();
var _formKey = GlobalKey<FormState>();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login"),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Center(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Login",
style: TextStyle(
fontSize: 40, fontWeight: FontWeight.bold)),
SizedBox(height: 40,),
TextFormField(
controller: emailController,
onFieldSubmitted: (String value) {
print(value);
},
onChanged: (String value) {
print(value);
},
validator: (String ?value) {
if (value == null || value.isEmpty) {
return 'the password must not be Empty';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "E-mail Address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
prefixIcon: Icon(Icons.email),
),
),
SizedBox(height: 20,),
TextFormField(
controller: PasswordController,
obscureText: true,
keyboardType: TextInputType.visiblePassword,
validator: (String ?value) {
if (value == null || value.isEmpty) {
return 'the password must not be Empty';
}
return null;
},
onFieldSubmitted: (String value) {
print(value);
},
onChanged: (String value) {
print(value);
},
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)),
prefixIcon: Icon(Icons.lock),
suffixIcon: Icon(Icons.remove_red_eye_rounded)
)
),
SizedBox(height: 20,),
defaultButton(
background: Colors.black26,
isUpperCase: true,
text: "Login",
function: () {
if (_formKey.currentState!.validate()) ==> // Null check operator
used on a null value.
{
print(emailController);
print(PasswordController);
}
}
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Already you Have account?"),
TextButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => Registry()));
},
child: Text("Register now "))
],
),
],
),
),
),
),
),
);
}
}
Hey what you're using is called the non-null assertion operator, it actually means you are saying that value can't be null. If you want to make sure it's not null before trying to access validate(), you should use optional chaining _formKey.currentState?.validate()
What you can also try to do is check that it's not null before you call validate().
if (!!_formkey.currentState && _formKey.currentState.validate())

Error: The parameter 'onSubmit' can't have a value

Hi I have created a default form field, in a separate dart file called components, and I have login_screen.dart also.
there are many errors I don't know how to fix it, and make the code work, I will put down the code of the component.dart code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget defaultButton(
{double width = double.infinity,
Color background = Colors.blue,
double radius = 10.0,
required Function function,
required String text,
bool isUpperCase = true}) =>
Container(
height: 40.0,
width: width,
child: MaterialButton(
onLongPress: () {},
onPressed: function(),
child: Text(
isUpperCase ? text.toUpperCase() : text.toLowerCase(),
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadiusDirectional.circular(radius),
color: background,
),
);
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function onSubmit,
Function onChange,
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit(),
onChanged: onChange(),
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);
and here is the code of the login_screen.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:udemy_flutter/shared/components/components.dart';
class LoginScreen extends StatelessWidget {
var emailController = TextEditingController();
var passController = TextEditingController();
var formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Login',
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold
),
),
const SizedBox(
height: 40.0,
),
defaultFormFeild(
controller: emailController,
label: 'Email',
prefix: Icons.email,
type: TextInputType.emailAddress,
validate: (String value){
if(value.isEmpty != null){
return 'Email Cannot Be Empty';
}
return null;
}
),
const SizedBox(
height: 15.0,
),
TextFormField(
controller: passController,
obscureText: true,
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
prefixIcon: Icon(
Icons.lock
),
suffixIcon: Icon(
Icons.remove_red_eye,
)
),
onChanged: (value) {
print(value);
},
onFieldSubmitted: (value) {
print(value);
},
validator: (value) {
if(value!.isEmpty){
return 'Password cannot be empty';
}
return null;
},
),
const SizedBox(
height: 10.0,
),
defaultButton(
function: (){
print(emailController.text);
print(passController.text);
},
text: 'Login',
),
const SizedBox(
height: 10.0,
),
defaultButton(
text: 'ReGister',
function: () {
print('You have just clicked on register');
},
background: Colors.red,
isUpperCase: false
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Don\'t you have an account?'),
TextButton(onPressed: () {}, child: const Text(
'Register Now'
))
],
)
],
),
),
),
),
),
);
}
}
Idk if all the problems came from a null-safety feature in a flutter because I'm new in this technology.
Why
The reason this happens is because with null safety enabled, your functions onSubmit and onChange can't be null.
Solution
I would do it this way:
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit, //Add question mark
Function? onChange, //Add question mark
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit != null? onSubmit() : null, //do null checking
onChanged: onChange != null? onChange() : null, //do null checking
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);

how to resolve unexpected null value

I added a float button in my application while clicking on it two text-field appear , without adding formKey the button works but when i use it to controle if the field text are empty or not by if statement if (formKey.currentState!.validate()) in the Debug Console i get this error
════════ Exception caught by gesture ═══════════════════════════════════════════
Unexpected null value.
═══════════════════════════════════════════════════════════════════════════════
this the code of floating button
floatingActionButton: FloatingActionButton(
onPressed: () {
if (isBottomSheetShown) {
if (formKey.currentState!.validate()) {
Navigator.pop(context);
isBottomSheetShown = false;
setState(() {
fabIcon = Icons.edit;
});
}
} else {
scaffoldKey.currentState!.showBottomSheet(
(context) => Container(
color: Colors.grey[100],
padding: const EdgeInsets.all(20),
child: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: titleController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.title),
hintText: 'write a title',
labelText: 'Title',
border: OutlineInputBorder(),
),
),
SizedBox(
height: 15,
),
TextField(
controller: timeController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.watch_later_outlined),
hintText: 'write a time',
labelText: 'Time',
border: OutlineInputBorder(),
),
onTap: () {
showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
).then((value) {
timeController.text =
value!.format(context).toString();
print(value!.format(context));
});
},
),
],
),
),
),
);
}
isBottomSheetShown = true;
setState(() {
fabIcon = Icons.add;
});
},
child: Icon(
fabIcon,
)),
The Unexpected null value is occurring because you're asserting that formKey.currentState is not null before you validate it, so if currentState equals null, it will throw that error.
I'd suggest first checking if formKey.currentState != null before calling the validate method.

Catch tap event on TextFormField

I am trying to catch the tap event on TextFormField into a flutter Form.
I use a GestureDetector to do that with the TextFormField as child but nothing is firing when a click on it :
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(title: const Text('Recherche de sorties')),
body: new DropdownButtonHideUnderline(
child: new Form(
key: _formKey,
autovalidate: _autovalidate,
child: new ListView(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
children: <Widget>[
new DatePicker(
labelText: 'Date',
selectedDate: widget.request.dateDebut,
initialDate: widget.request.dateDebut,
firstDate: new DateTime.now().add(new Duration(days: -1)),
lastDate: new DateTime.now().add(new Duration(days: 365 * 4)),
selectDate: (DateTime value) {
setState(() {
widget.request.dateDebut = value;
});
},
datePickerMode: DatePickerMode.day,
icon: const Icon(Icons.date_range),
),
new InputDecorator(
decoration: const InputDecoration(
labelText: 'Rayon',
hintText: '-- Choisissez un rayon --',
icon: const Icon(Icons.settings_backup_restore),
),
isEmpty: widget.request.rayon == null,
child: new DropdownButton<String>(
value: widget.request.rayon.toString(),
isDense: true,
onChanged: (String newValue) {
setState(() {
widget.request.rayon = int.parse(newValue);
});
},
items: _rayons.keys.map((int key) {
return new DropdownMenuItem<String>(
value: key.toString(),
child: new Text(_rayons[key]),
);
}).toList(),
),
),
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new TextFormField(
// controller: controller,
decoration: const InputDecoration(
icon: const Icon(Icons.room),
hintText: 'Où êtes vous ?',
labelText: 'Localisation',
),
),
),
new Container(
padding: const EdgeInsets.all(20.0),
alignment: Alignment.center,
child: new Align(
alignment: const Alignment(0.0, -0.2),
child: new ButtonBar(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new RaisedButton(
child: const Text('ANNULER'),
onPressed: _fermerCritereRecherche,
),
new RaisedButton(
child: const Text('VALIDER'),
onPressed: _valider,
),
],
),
)),
]),
),
),
);
}
If i replace :
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new TextFormField(
// controller: controller,
decoration: const InputDecoration(
icon: const Icon(Icons.room),
hintText: 'Où êtes vous ?',
labelText: 'Localisation',
),
),
),
By a simple Container it is working :
new GestureDetector(
onTap: () async {
print("Container clicked");
Prediction p = await showGooglePlacesAutocomplete(
context: context,
apiKey: Consts.googlePlacesApiKey,
mode: Mode.fullscreen,
language: "fr",
components: [new Component(Component.country, "fr")]);
if (p != null) {
(_scaffoldKey.currentState).showSnackBar(
new SnackBar(content: new Text(p.description)));
}
},
child: new Container(
width: 80.0,
height: 80.0,
margin: new EdgeInsets.all(10.0),
color: Colors.black),
),
Do you have any ideas how to make GestureDetector work with TextFormField ? Maybe with a controller but i have tried without any success
Thanks in advance
Simply use onTap Method of TextFormField:
TextFormField(
onTap: () {
print("I'm here!!!");
}
)
Wrap TextFormField widget With AbsorbPointer widget , then OnTap() works definitely
here is an example:-
GestureDetector(
onTap: () => dialog(),
child: AbsorbPointer(
child: TextFormField(
textInputAction: TextInputAction.newline,
decoration: new InputDecoration(
fillColor: Colors.grey,
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(6.0)),
borderSide:
BorderSide(color: Colors.grey[100]),
gapPadding: 4),
labelText: "Enter your mood",
labelStyle: TextStyle(
letterSpacing: 1,
color: Colors.grey,
fontSize: 13),
hintMaxLines: 1),
validator: (val) {
if (val == "") return "Field can't be empty";
},
keyboardType: TextInputType.text,
enabled: true,
textAlign: TextAlign.justify,
minLines: 3,
autofocus: false,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
),
maxLines: 10,
),
),
),
Wrap AbsorbPointer Widget with Gesture Detector, and then work in onTap(). it will work fine.
I have found a solution by using the InputDecorator (from the flutter gallery) :
child: new InputDecorator(
decoration: const InputDecoration(
labelText: 'Localisation',
icon: const Icon(Icons.room),
),
child: widget.request.localisationLibelle != null
? new Text(widget.request.localisationLibelle)
: new Text("-- Choisissez un lieu --"),
),
Instead of using a TextFormField that catch the tap at the place of the GestureDetector I use a simple child Text of the InputDecorator widget.
I just solved this myself using Flutter 0.6.0.
The GestureDetector object takes in a behavior property from this enum to determine how to defer actions.
Small snippet of the GestureDetector taking priority over a TextFormField:
new GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: new TextFormField(
enabled: onTap == null,
*other stuff here*
),
)
The onTap object is a Function object I declare outside of this. I also set the enabled property based on my onTap object, so I can ensure that if I want to capture a tap, the text form field is disabled.
onTap function is working but if you use it with InputDecoration { enabled: false }, it will not working.
decoration: InputDecoration(
enabled: false, // not working when on tap
isDense: true,
filled: true,
fillColor: _listRadioItemPosition.isEmpty ? Colors.grey[100] : Colors.white,
border: UnderlineInputBorder(borderSide: BorderSide(color: Color(0xFFC4C4C4), width: 1)),
),
onTap: (){
displayBottomSheetPosition(context);
},