I have mu custom DropDown Widget.
class DropDownMenuField extends StatefulWidget {
String title;
final InputDecoration decoration;
final String Function(String) validator;
final void Function(dynamic value) onSelectionDone;
final String initialValue;
final Color selectedItemColor;
final DropMenuMode menuMode;
int selectvalueindex;
final Function(String) onChanged;
var model;
DropDownMenuField(
{Key key,
this.title,
this.decoration,
this.validator,
this.onSelectionDone,
this.initialValue,
this.selectedItemColor,
this.model,
this.menuMode,
this.selectvalueindex,
this.onChanged})
: super(key: key);
#override
State<DropDownMenuField> createState() => _DropDownMenuFieldState();
}
class _DropDownMenuFieldState extends State<DropDownMenuField> {
final TextEditingController _controller = TextEditingController();
void _popUpModalBottomSheet(BuildContext context) async {
List<String> finalDataList = [];
List<dynamic> dataMap = await apiRegistrationDataList(widget.menuMode);
finalDataList = parseMap(dataMap);
final result = await showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(9.0),
),
isScrollControlled: true,
context: context,
builder: (context) => DialogMenu(
title: widget.title,
data: finalDataList,
));
if (result == null) {
widget.title = widget.title;
_controller.text = widget.title;
} else {
// widget.title = result ?? widget.title;
// lab
labStyle = checkedLableStyle;
lable = result;
_controller.text = result;
widget.onSelectionDone(result);
widget.validator(result);
setState(() {});
}
SetGlobalRequaerData(result, dataMap);
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _popUpModalBottomSheet(context),
child: TextFormField(
controller: _controller,
readOnly: true,
enabled: false,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: widget.validator,
onChanged: widget.onChanged,
style: const TextStyle(
fontSize: 16,
color: Color(0xFF3C3C43),
),
decoration: InputDecoration(
labelStyle: labStyle,
hintStyle: TextStyle(
fontFamily: 'FiraSans',
color: GeneralStyles.greyColor,
),
fillColor: Colors.white,
filled: true,
contentPadding: const EdgeInsets.fromLTRB(16, 0, 0, 0),
errorStyle: const TextStyle(
color: Colors.red,
fontFamily: 'FiraSans',
fontWeight: FontWeight.w400,
fontSize: 13),
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
color: GeneralStyles.greyColor.withOpacity(0.5),
width: .5)),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(color: Color(0xFF707070), width: .5)),
disabledBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(4)),
borderSide:
BorderSide(color: GeneralStyles.greyColor, width: .5)),
focusedBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(4)),
borderSide:
BorderSide(color: GeneralStyles.blackColor, width: 1)),
errorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(color: Colors.red, width: .5),
),
labelText: lable,
hintText: widget.title,
suffixIcon: Icon(
Icons.keyboard_arrow_down,
color: GeneralStyles.greyColor,
),
),
));
}
}
And i call it on my registration page.
DropDownMenuField(
title: "Anrede",
model: widget.model,
menuMode: DropMenuMode.genders,
selectvalueindex: 0,
onSelectionDone: (value){
print(value);
},
validator: (value){
if(widget.model.selectedDropMenu[0].isEmpty){
return 'Bitte fülle das Feld aus';
}
return null;
},
),
When i click button when DropDownMenuField selectedValue is empty validator is work but when i select value widget don't call validator and don't change color from red. How call validator after change value. I read that when texteditingcontroller is changed, calling validator after him. i add it but not work.
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.
i'm trying to use customTextField
this the file which contain the Widget
import 'package:flutter/material.dart';
Widget defaultFormField({
required TextEditingController controller,
required TextInputType type,
required Function validate,
Function? onSubmitted,
Function? onChange,
Function? onTap,
required String label,
required IconData prefix,
}) =>
Form(
child: TextFormField(
controller: controller,
validator: (value) => validate(value),
// validator: validate(),
onFieldSubmitted: onSubmitted!(),
onChanged: onChange!(),
onTap: onTap!(),
keyboardType: type,
decoration: InputDecoration(
labelText:label,
prefixIcon: Icon(prefix),
border: const OutlineInputBorder(),
),
),
);
and this how i call it
in my home page
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
backgroundColor: Colors.red,
title: Text(titles[currentIndex]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.redAccent,
onPressed: () {
if (isBottomSheet) {
Navigator.pop(context);
isBottomSheet = false;
setState(() {
fabIcon = Icons.edit;
});
} else {
scaffoldKey.currentState?.showBottomSheet(
(context) => Column(mainAxisSize: MainAxisSize.min, children: [
Form(
key: formdKey,
child: defaultFormField(
controller: titleController,
type: TextInputType.text,
validate: (String value) {
if (value.isEmpty) {
return 'title must not be empty';
}
return null;
},
label: 'Title Task',
prefix: Icons.title),
),
]));
isBottomSheet = true;
setState(() {
fabIcon = Icons.add_task;
});
}
},
child: Icon(fabIcon),
),
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Colors.white,
unselectedItemColor: Colors.black54,
backgroundColor: Colors.red,
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
onTap: (value) {
setState(() {
currentIndex = value;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.new_label), label: 'Tasks'),
BottomNavigationBarItem(
icon: Icon(Icons.check_circle), label: 'Done'),
BottomNavigationBarItem(
icon: Icon(Icons.archive), label: 'Archive'),
]),
body: screens[currentIndex],
);
}
You have to use a class instead of that code, your code is wrong.
This is one of my custom TextFormField.
This contains own another class but anyway you can use this:
import 'package:flutter/material.dart';
import 'package:plasco/config/textfield_validator.dart';
import 'package:plasco/utils/colors.dart';
class PlascoTextFormFild extends StatefulWidget {
final String? text;
final FontWeight? fontWeight;
final double? fontSize;
final double? counterFontSize;
final TextAlign? textAlign;
final TextInputType? keyboardType;
final int? maxLength;
final String? hint;
final int? maxLines;
final Color? color;
final TextEditingController? controller;
final bool? enabled;
final Validator? validator;
final bool publicValidator;
const PlascoTextFormFild(
{Key? key,
this.text,
this.fontWeight,
this.publicValidator = false,
this.fontSize,
this.color = Colors.transparent,
this.counterFontSize,
required this.textAlign,
this.keyboardType,
this.maxLength = 800,
this.hint,
this.maxLines,
this.controller,
this.enabled = true,
this.validator})
: super(key: key);
#override
_PlascoTextFormFildState createState() => _PlascoTextFormFildState();
}
class _PlascoTextFormFildState extends State<PlascoTextFormFild> {
bool _focused = false;
bool _hasError = false;
String _error = '';
late FocusNode? _keyboardFocus;
#override
void initState() {
_keyboardFocus = FocusNode();
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
_keyboardFocus!.addListener(() {
setState(() {
if (!_keyboardFocus!.hasPrimaryFocus) {
_focused = false;
}
});
});
return Directionality(
textDirection: TextDirection.rtl,
child: Container(
decoration: BoxDecoration(
color: widget.color,
borderRadius: BorderRadius.circular(5),
),
child: TextFormField(
controller: widget.controller,
enabled: widget.enabled,
cursorHeight: 20,
textDirection: TextDirection.rtl,
focusNode: _keyboardFocus,
maxLines: widget.maxLines,
maxLength: widget.maxLength,
textAlign: widget.textAlign!,
keyboardType: widget.keyboardType,
validator: (text) {
if (widget.validator == null) {
if (widget.publicValidator) {
var a = PublicValidator(text!, widget.text!);
if (a) {
return "";
} else {
return null;
}
} else {
return null;
}
} else {
if (widget.validator!.hasError(text!)) {
setState(() => _hasError = true);
_error = widget.validator!.getError();
return '';
} else {
setState(() => _hasError = false);
return null;
}
}
},
style: TextStyle(
color: PlascoColor.Black1,
fontFamily: 'IRANSansMobile',
fontSize: widget.fontSize,
letterSpacing: 0,
fontWeight: widget.fontWeight,
height: widget.maxLines != null ? 2 : 1),
decoration: InputDecoration(
counterText: "",
labelStyle: TextStyle(
color: _hasError
? PlascoColor.Red1
: _focused
? PlascoColor.Yellow1
: PlascoColor.Gray1,
fontFamily: 'IRANSansMobile',
fontSize: widget.fontSize,
letterSpacing: 0,
fontWeight: widget.fontWeight,
height: 1,
),
hintStyle: TextStyle(
color: PlascoColor.Gray2,
fontFamily: 'IRANSansMobile',
fontSize: widget.fontSize,
letterSpacing:
0 /*percentages not used in flutter. defaulting to zero*/,
fontWeight: widget.fontWeight,
height: 1),
counterStyle: TextStyle(
color: PlascoColor.Gray1,
fontFamily: 'IRANSansMobile',
fontSize: widget.counterFontSize,
letterSpacing: 0,
fontWeight: widget.fontWeight,
height: 1),
floatingLabelBehavior: FloatingLabelBehavior.always,
// border: OutlineInputBorder(),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: PlascoColor.Gray2,
width: 1.0,
)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: PlascoColor.Gray2,
width: 1.0,
)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: PlascoColor.Yellow1,
width: 1.0,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: PlascoColor.Red1,
width: 1.0,
)),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
borderSide: const BorderSide(
color: PlascoColor.Red1,
width: 1.0,
)),
labelText: _hasError ? _error : widget.text,
hintText: widget.hint,
contentPadding: EdgeInsets.fromLTRB(8, 8, 8, 8),
),
// autofocus: false,
),
),
);
}
}
I'm trying to get info from my db using http get method, but when I try to get data, it returns the error:
E/flutter (15407): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
Here is the code:
// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables
import 'dart:convert';
import 'package:apetit_project/models/app_user.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/auth_form_data.dart';
import 'package:http/http.dart' as http;
class AuthForm extends StatefulWidget {
final void Function(AuthFormData) onSubmit;
const AuthForm({
Key? key,
required this.onSubmit,
}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final _formData = AuthFormData();
String _teste = '[]';
final _url = 'http://172.16.30.120:8080/ords/apiteste/integrafoods/users';
#override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
bool isLogin = true;
late String title;
late String actionButton;
late String toggleButton;
void _submit() {
final isValid = _formKey.currentState?.validate() ?? false;
if (!isValid) return;
widget.onSubmit(_formData);
}
Future<void> _loadUsers() async {
final response = await http.get(Uri.parse(_url));
Map<String, dynamic> data = jsonDecode(response.body);
data.forEach(
(userId, userData) {
_teste = userData['nome'];
},
);
print(_teste);
// $_url/${newComment.comment}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/Login.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Container(
margin: const EdgeInsets.only(bottom: 30),
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_formData.isSignup)
TextFormField(
key: const ValueKey('Nome'),
initialValue: _formData.name,
onChanged: (name) => _formData.name = name,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
labelText: 'Nome',
labelStyle: const TextStyle(color: Colors.black),
),
keyboardType: TextInputType.emailAddress,
),
if (_formData.isLogin)
TextFormField(
// controller: _emailController,
key: const ValueKey('Email'),
initialValue: _formData.email,
onChanged: (email) => _formData.email = email,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Image.asset(
'assets/images/email_icon.png',
scale: 6,
color: Colors.black,
),
labelText: 'Email',
labelStyle: const TextStyle(color: Colors.black),
),
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 20,
),
if (_formData.isLogin)
TextFormField(
// controller: _passwordController,
key: const ValueKey('password'),
initialValue: _formData.password,
onChanged: (password) => _formData.password = password,
style: const TextStyle(color: Colors.black),
obscureText: true,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Senha',
labelStyle: const TextStyle(color: Colors.black)),
validator: (_password) {
final password = _password ?? '';
if (password.length < 6) {
return 'Senha deve ter no mínimo 6 caracteres';
}
return null;
},
),
const SizedBox(
height: 20,
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
// onPressed: _signInUser,
onPressed: _loadUsers,
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary),
),
child: Text(
_formData.isLogin ? 'Entrar' : 'Cadastrar',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
),
),
TextButton(
onPressed: () {
setState(() {
_formData.toggleAuthMode();
});
},
child: Text(
_formData.isLogin
? 'Criar uma nova conta?'
: 'Já possui conta?',
),
),
],
),
),
),
),
),
);
}
Future _signInUser() async {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
}
}
{
"items": [
{
"id": 1,
"login": "1234567",
"nome": "Ricardo",
"situacao": "A",
"telefone": "(14) 99797-5621",
"senha": "124578",
"dt_inclusao": null,
"usu_inclusao": null,
"dt_alteracao": null,
"usu_alteracao": null
}
],
"hasMore": false,
"limit": 25,
"offset": 0,
"count": 1,
"links": [
{
"rel": "self",
"href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
},
{
"rel": "describedby",
"href": "http://172.16.30.120:8080/ords/apiteste/metadata-catalog/integrafoods/item"
},
{
"rel": "first",
"href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
}
]
}
I added the full widget code and the JSON. I am seeking a working example so I can understand why it's not working.
It's look like you have in userDat variable some sort of List. It dosen't have key:value pair like Map. Yo need to run through List indexes.
Try to use
_teste = userData[0]['nome'];
And look what happens.
You need to look on JSON structure you receive from the server. If you show here JSON structure it will help to find right solution for you.
I have a List of items that I retrieve from a database with http.get method. I need to create a validator that only allow users to submit if the value typed is equal to at least one of the values of the list.
Example: The list is: [{name: Peter, email: peter#gmail.com}{name: Mathew, email: mtw#gmail.com}]. Then I have two textFormFields, one for NAME and another for EMAIL. So if the NAME and EMAIL the user types match any of the items of the list, than user can submit. I created the http.get method and I created the TextFormfields, but I cannot figure how to create the validator.
Here is the Formulary code:
// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables
import 'dart:convert';
import 'package:apetit_project/components/teste_app_users_item.dart';
import 'package:apetit_project/models/app_user.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/auth_form_data.dart';
import 'package:http/http.dart' as http;
import '../models/user_data.dart';
class AuthForm extends StatefulWidget {
final void Function(AuthFormData) onSubmit;
const AuthForm({
Key? key,
required this.onSubmit,
}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final _formData = AuthFormData();
List<dynamic> _teste = [];
List<dynamic> get teste => [..._teste];
final _url = 'URL';
#override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
bool isLogin = true;
late String title;
late String actionButton;
late String toggleButton;
void _submit() {
final isValid = _formKey.currentState?.validate() ?? false;
if (!isValid) return;
widget.onSubmit(_formData);
}
Future<void> _loadUsers() async {
final response = await http.get(
Uri.parse('http://172.16.30.120:8080/ords/apiteste/integrafoods/users'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.body == 'null') return;
final data = jsonDecode(response.body)['items'] as List?;
if (data != null) {
// _teste = data;
_teste = data.map((e) => MyItem.fromMap(e)).toList();
print(data);
}
// print(_teste.toList());
}
#override
_initState() {
_loadUsers();
super.initState();
}
#override
Widget build(BuildContext context) {
// print(_teste);
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/Login.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Container(
margin: const EdgeInsets.only(bottom: 20),
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_formData.isSignup)
TextFormField(
key: const ValueKey('Nome'),
initialValue: _formData.name,
onChanged: (name) => _formData.name = name,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Nome',
labelStyle: const TextStyle(color: Colors.black),
),
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 4,
),
TextFormField(
// controller: _emailController,
key: const ValueKey('Email'),
initialValue: _formData.email,
onChanged: (email) => _formData.email = email,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Image.asset(
'assets/images/email_icon.png',
scale: 6,
color: Colors.black,
),
labelText: 'Email',
labelStyle: const TextStyle(color: Colors.black),
),
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 4,
),
TextFormField(
// controller: _passwordController,
key: const ValueKey('password'),
initialValue: _formData.password,
onChanged: (password) => _formData.password = password,
style: const TextStyle(color: Colors.black),
obscureText: true,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Senha',
labelStyle: const TextStyle(color: Colors.black)),
validator: (_password) {
final password = _password ?? '';
if (password.length < 6) {
return 'Senha deve ter no mínimo 6 caracteres';
}
return null;
},
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: _loadUsers,
child: Text('teste'),
),
// Expanded(
// child: ListView.builder(
// itemBuilder: (ctx, index) {
// return Card(
// child: ClipRRect(child: MyItemItem(_teste[index])));
// },
// itemCount: _teste.length,
// ),
// ),
SizedBox(
width: double.infinity,
child: ElevatedButton(
// onPressed: _signInUser,
onPressed: _submit,
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary),
),
child: Text(
_formData.isLogin ? 'Entrar' : 'Cadastrar',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
),
),
TextButton(
onPressed: () {
setState(() {
_formData.toggleAuthMode();
});
},
child: Text(
_formData.isLogin
? 'Criar uma nova conta?'
: 'Já possui conta?',
),
),
],
),
),
),
),
),
);
}
// Future _signInUser() async {
// await FirebaseAuth.instance.signInWithEmailAndPassword(
// email: _emailController.text,
// password: _passwordController.text,
// );
// }
}
and here is the "My item" class
import 'dart:convert';
class MyItem {
final int id;
final String email;
final String? cpf;
MyItem({
required this.id,
required this.email,
required this.cpf,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'sequencia': id});
if (email != null) {
result.addAll({'email': email});
}
if (cpf != null) {
result.addAll({'cpf': cpf});
}
return result;
}
factory MyItem.fromMap(Map<String, dynamic> map) {
return MyItem(
id: int.tryParse(map['sequencia'].toString()) ?? 0,
email: map['email'],
cpf: map['cpf'],
);
}
String toJson() => json.encode(toMap());
factory MyItem.fromJson(String source) => MyItem.fromMap(json.decode(source));
}
How can I fix it?
The following should do the trick. Do the same for name and you're good to go.
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
if (!_teste.any((item) => item.email == email)) { // <- Here
return 'E-mail já cadastrado.'; // <- Here
}
return null;
},
TextFormField(
style: TextStyle(color: Colors.black),
textAlign: TextAlign.center,
controller: _HeightController,
validator: (value) {
if (value!.trim().isEmpty) {
return 'enter some text';
} else {
return null;
}
},
decoration:InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: pro.backColor_main,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: Color(0xffC2C2C2),
width: 2.0,
),
),
hintText: '키를 입력해주세요',
hintStyle: TextStyle(fontSize: 13.sp,
color: Color(0xffA9A9A9),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
fillColor: Colors.white,
filled: true,
),
keyboardType: TextInputType.number,
),
This is my textformfield code.
Changing color when TextFormField is selected
Changing color when TextFormField is not selected
I understand that changing the color of the border of TextFormField itself.
But I want to keep the color of pro.main(blue) after a value is entered in TextFormField
This is because if you deselect the selection after entering a value, it becomes gray.
In this case, I wonder if there is a code to change the outline color if there is a value in the TextFormField.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late TextEditingController _HeightController;
#override
void initState() {
_HeightController = TextEditingController();
}
#override
void dispose() {
_HeightController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: TextFormField(
style: TextStyle(color: Colors.black),
textAlign: TextAlign.center,
controller: _HeightController,
validator: (value) {
if (value!.trim().isEmpty) {
return 'enter some text';
} else {
return null;
}
},
onChanged: (_){
setState(() {
});
},
decoration:InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: Colors.indigo,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: _HeightController.value.text.isEmpty ? Color(0xffC2C2C2) : Colors.blueAccent,
width: _HeightController.value.text.isEmpty ? 2.0 : 3.0,
),
),
hintText: '키를 입력해주세요',
hintStyle: TextStyle(fontSize: 13,
color: Color(0xffA9A9A9),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
fillColor: Colors.white,
filled: true,
),
keyboardType: TextInputType.number,
),
),
);
}
}
when it's empty :
when it's not empty :
you can try that, define a bool variable. check textfield controller, if != "" or null set your color