Trouble accessing attribute from Stateful Widget - flutter

class PasswordTextField extends StatefulWidget {
final String hintText;
final IconData icon;
final TextEditingController controller;
final FormFieldValidator<String> validator;
PasswordTextField({
Key key,
this.hintText ,
this.icon = Icons.lock,
this.validator,
this.controller
}) : super(key: key);
#override
_PasswordTextFieldState createState() => _PasswordTextFieldState();
}
class _PasswordTextFieldState extends State<PasswordTextField> {
var _passwordVisible;
var _iconColor;
#override
void initState() {
_passwordVisible = true;
_iconColor = Colors.grey;
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return TextFieldContainer(
child: TextFormField(
controller: controller, //here
validator: validator, //here
obscureText: _passwordVisible,
cursorColor: kPrimaryightColor,
decoration: InputDecoration(
labelText: "Your Password",
labelStyle: TextStyle(color: kPrimaryColor) ,
hintText: hintText, /ere
border: InputBorder.none,
icon: Icon(
icon, //here
color: kPrimaryColor,
),
suffixIcon: IconButton(
icon: Icon(Icons.remove_red_eye),
color: _iconColor,
onPressed: (){
setState(() {
if(_passwordVisible == true){
_passwordVisible = false;
_iconColor = kPrimaryColor;
}else{
_passwordVisible = true;
_iconColor = Colors.grey;
}
});
},
),
),
),
);
}
#override
State<StatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}
I want to access some attribute from my stateful widget, but I don't know how, it work like this in stateless, is there any another way to use this on another file?
I use it like this
PasswordTextField(
validator:(value){
if(value.isEmpty){
return "Please insert something";
}else if(value.length < 6){
return "Enter Correct Password Format (6 character)";
}else{
return null;
}

You can access the fields declared in your Stateful widget class in the state class by using the predefined field widget i.e. widget.controller. So your code will look like this:
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
controller: widget.controller, // here
validator: widget.validator, // here
obscureText: _passwordVisible,
cursorColor: kPrimaryightColor,
decoration: InputDecoration(
labelText: "Your Password",
labelStyle: TextStyle(color: kPrimaryColor) ,
hintText: widget.hintText, // here
border: InputBorder.none,
icon: Icon(
widget.icon, // here
color: kPrimaryColor,
),
// Define other controls
),
),
);
}

Related

What is the solution for the "Invalid constant value" error [duplicate]

This question already has answers here:
Invalid Constant Value using variable as parameter
(9 answers)
Closed 22 days ago.
I am getting an error in my Flutter app when trying to run it. The error message is "Invalid constant value." and it is pointing to this specific line (line 4 and 45) of code (obscureText).
The error seems to be related to the use of the const keyword in this line. I am trying to create a to hide and show password text, but the const keyword is causing an issue. Can someone please explain what this error means and how I can resolve it in my code?
import 'package:flutter/material.dart';
void main() {
runApp(const RunMyApp());
}
class RunMyApp extends StatefulWidget {
const RunMyApp({super.key});
#override
State<RunMyApp> createState() => _RunMyAppState();
}
class _RunMyAppState extends State<RunMyApp> {
bool passwordVisible = false;
final passwordController = TextEditingController();
bool obscureText = false;
#override
void initState() {
super.initState();
passwordVisible = true;
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Show or Hide Password in TextField'),
),
body: Container(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
keyboardType: TextInputType.text,
controller: passwordController,
obscureText: !obscureText,
decoration: const InputDecoration(
hintText: 'Password',
prefixIcon: Icon(Icons.lock_open),
suffixIcon: IconButton(
icon: Icon(obscureText
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
setState(() {
obscureText = !obscureText;
});
}),
),
validator: (value) {
if (value!.isEmpty) {
return 'Enter password';
}
return null;
},
),
)));
}
}
You cant create const InputDecoration because the icon and onPressed is depended/changes on run time.
Remove the const before decoration: InputDecoration(
decoration: InputDecoration(
hintText: 'Password',
prefixIcon: const Icon(Icons.lock_open),
suffixIcon: IconButton(
icon: Icon(obscureText
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
setState(() {
obscureText = !obscureText;
});
}),
),
Try the following code:
import 'package:flutter/material.dart';
void main() {
runApp(const RunMyApp());
}
class RunMyApp extends StatefulWidget {
const RunMyApp({super.key});
#override
State<RunMyApp> createState() => _RunMyAppState();
}
class _RunMyAppState extends State<RunMyApp> {
bool passwordVisible = false;
final passwordController = TextEditingController();
bool obscureText = false;
#override
void initState() {
super.initState();
passwordVisible = true;
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.green),
home: Scaffold(
appBar: AppBar(
title: const Text('Show or Hide Password in TextField'),
),
body: Container(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
keyboardType: TextInputType.text,
controller: passwordController,
obscureText: !obscureText,
decoration: InputDecoration(
hintText: 'Password',
prefixIcon: const Icon(Icons.lock_open),
suffixIcon: IconButton(
icon: Icon(obscureText ? Icons.visibility : Icons.visibility_off),
onPressed: () {
setState(() {
obscureText = !obscureText;
});
},
),
),
validator: (value) {
if (value!.isEmpty) {
return 'Enter password';
}
return null;
},
),
),
),
);
}
}

Flutter PWA - Canvas going to change after dismiss keyboard

I am facing one strange issue in the flutter progressive web application. It's working well in safari and chrome browsers. It's creating an issue when we add it to the home screen. We are having only two text fields on the page and nothing else. After opening a keyboard and clicking on the done or return button then we tap outside the TextInput area multiple times(5 - 6 times) then the canvas(body) of the page reduces gradually. Please check the attached video for it. Video Link
Please check below code:
import 'package:demo_texfield_web/unfocser.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TextfieldDemo(),
);
}
}
class TextfieldDemo extends StatefulWidget {
const TextfieldDemo({Key? key}) : super(key: key);
#override
State<TextfieldDemo> createState() => _TextfieldDemoState();
}
class _TextfieldDemoState extends State<TextfieldDemo> {
var txtxField1 = TextEditingController();
var txtxField2 = TextEditingController();
FocusNode _focusNode1 = new FocusNode();
FocusNode _focusNode2 = new FocusNode();
final _formKey = GlobalKey<FormState>();
int count = 0;
#override
void initState(){
super.initState();
_focusNode1.addListener(_focusNodeListener);
}
#override
void dispose(){
_focusNode1.removeListener(_focusNodeListener);
super.dispose();
}
Future<Null> _focusNodeListener() async {
if (_focusNode1.hasFocus){
print('TextField got the focus');
} else {
print('TextField lost the focus');
FocusScope.of(context).unfocus();
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if(!currentFocus.hasPrimaryFocus) {
currentFocus.focusedChild!.unfocus();
}
},
child: Scaffold(
body:Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(60.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Unfocuser(
child: TextFormField(
decoration: const InputDecoration(
border: UnderlineInputBorder(),
filled: true,
icon: Icon(Icons.person),
hintText: 'Enter your first name',
labelText: 'First name *',
),
onSaved: (String? value) {
//TODO
},
controller: txtxField1,
focusNode: _focusNode1,
),
),
const SizedBox(height: 25,),
Unfocuser(
child: TextFormField(
keyboardType: TextInputType.number,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
filled: true,
icon: const Icon(Icons.person),
hintText: 'Enter your Last name',
labelText: 'Last name *',
),
onSaved: (String? value) {
//TODO
},
controller: txtxField2,
focusNode: _focusNode2,
),
),
],
),
),
),
),
);
}
}

Flutter: How can I set initial value to a textController and change it after?

I have a stepper and some TextFormFields with controller in the first step. I want to show in the TextField an initialValue and if I change the value want to set the new value to the controller and keep it on change step.
Now, I can change the value of the controller but not keep it on change step
Edit Page
class EditProfilePage extends StatefulWidget {
final String uid;
const EditProfilePage({Key? key, required this.uid}) : super(key: key);
#override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
final TextEditingController _nameController = TextEditingController();
int _index = 0;
#override
void initState() {
super.initState();
_nameController.addListener(() {
final String text = _nameController.text;
_nameController.value = _nameController.value.copyWith(
text: text,
);
});
}
#override
void dispose() {
super.dispose();
_nameController.dispose();
}
#override
Widget build(BuildContext context) {
;
final UserProvider userProvider = Provider.of<UserProvider>(context);
_nameController.text = userProvider.getUser.name;
return Scaffold(
...
body: Stepper(
controlsBuilder: (BuildContext context, ControlsDetails details) {
if (_index == 2) {
return Container(
padding: const EdgeInsets.only(right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
userProvider.updateName(
_nameController.text, userProvider.getUser.uid);
},
child: const Text('SAVE'),
),
],
),
);
} else {
return Row();
}
},
currentStep: _index,
onStepCancel: () {
_index > 0 ? setState(() => _index -= 1) : null;
},
onStepContinue: () {
_index < 2 ? setState(() => _index += 1) : null;
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
steps: <Step>[
Step(
title: const Text('Personal Info'),
content: Container(
padding: const EdgeInsets.all(5),
child: Column(children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'Name',
labelStyle: const TextStyle(color: Colors.black54),
border: const OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context),
),
enabledBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context),
),
filled: true,
contentPadding: const EdgeInsets.all(8),
),
),
const SizedBox(
height: 24,
),
],
),
),
)
],
),
);
}
}
UserProvider
class UserProvider with ChangeNotifier {
User? _user;
final AuthMethods _authMethods = AuthMethods();
User get getUser => _user!;
Future<void> refreshUser() async {
User user = await _authMethods.getUserDetails();
_user = user;
notifyListeners();
}
}
You can use
TextEditingController.fromValue(TextEditingValue(text: "initial value"));
or
TextEditingController(text: "initial value")
Update
using nullable TextEditingController and getting context using WidgetsBinding.instance?.addPostFrameCallback inside initState to read provider.
class UserProvider with ChangeNotifier {
String userName = "intial UserName";
Future<void> setUser(String name) async {
userName = name;
notifyListeners();
}
}
class EditProfilePage extends StatefulWidget {
final String uid;
const EditProfilePage({Key? key, required this.uid}) : super(key: key);
#override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
TextEditingController? _nameController;
int _index = 0;
#override
void initState() {
super.initState(); // to have context
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
final provider = Provider.of<UserProvider>(context, listen: false);
debugPrint("Got Name : ${provider.userName}");
_nameController = TextEditingController(text: provider.userName);
_nameController?.addListener(() {
final text = _nameController == null ? "" : _nameController!.text;
provider.setUser(text);
});
setState(() {});
});
}
#override
void dispose() {
super.dispose();
_nameController?.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Consumer<UserProvider>(
builder: (context, value, child) {
return Text(value.userName);
},
),
TextFormField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'Name',
labelStyle: const TextStyle(color: Colors.black54),
border: const OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context),
),
enabledBorder: OutlineInputBorder(
borderSide: Divider.createBorderSide(context),
),
filled: true,
contentPadding: const EdgeInsets.all(8),
),
),
const SizedBox(
height: 24,
),
],
),
);
}
}
More about TextEditingController.
To set the initial value to a TextEditingController
final _nameController = TextEditingController(text: 'initial value');
And to update the value:
_nameController.text='new value';

I'm having issues trying to convert my StatelessWidget code..why?

I was trying to code a stateful widget on a statelessWidget class to put a bool and a stateState((), (show or hide password). So I followed some post which said that the solution is to convert.
I converted my class and I have some errors, maybe I should update my code but I don't know how to do that and I'm always getting errors like this:
36:32: Error: The setter '_isSecret' isn't defined for the class '_RoundedPasswordFieldState'.
-'_RoundedPasswordFieldState' is from 'package:yona/Login/Components/rounded_password_field.dart' ('lib/Login/Components/rounded_password_field.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named '_isSecret'.
Can you help me please ?
The problem is resolved, this is the new code
class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
bool _isSecret = true;
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
obscureText: _isSecret,
decoration: InputDecoration(
hintText: "Password",
border: InputBorder.none,
icon: Icon(
Icons.lock,
color: DarkTurquoise,
),
suffixIcon: InkWell(
onTap: () =>
setState(() => _isSecret = !_isSecret),
child: Icon(!_isSecret
? Icons.visibility
: Icons.visibility_off, color: DarkTurquoise),
),
),
),
);
}
}
To access _isSecret, you need to use widget.:
class RoundedPasswordField extends StatefulWidget {
final ValueChanged<String> onChanged;
const RoundedPasswordField({
required this.onChanged,
Key? key,
}) : super(key: key);
#override
_RoundedPasswordFieldState createState() => _RoundedPasswordFieldState();
}
class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
bool _isSecret = true;
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
obscureText:_isSecret,
decoration: InputDecoration(
hintText: "Password",
icon: Icon(
Icons.lock,
color: DarkTurquoise,
),
suffixIcon: InkWell(
onTap: () =>
setState(() => _isSecret = !_isSecret),
child: Icon(!_isSecret
? Icons.visibility
: Icons.visibility_off),
),
),
),
);
}
}
in setState you should change _isSecret to RoundedPasswordField._isSecret and the other problem is you are not calling onChanged.
working code:
class RoundedPasswordField extends StatefulWidget {
static bool _isSecret = true;
final ValueChanged<String> onChanged;
const RoundedPasswordField({
required this.onChanged,
Key? key,
}) : super(key: key);
#override
_RoundedPasswordFieldState createState() => _RoundedPasswordFieldState();
}
class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
obscureText: RoundedPasswordField._isSecret,
onChanged: widget.onChanged,
decoration: InputDecoration(
hintText: "Password",
icon: Icon(
Icons.lock,
color: DarkTurquoise,
),
suffixIcon: InkWell(
onTap: () =>
setState(() => RoundedPasswordField._isSecret = !RoundedPasswordField._isSecret),
child: Icon(!RoundedPasswordField._isSecret
? Icons.visibility
: Icons.visibility_off),
),
),
),
);
}
}
If you don't want to change _isSecret from outside of your widget then just use this code
class RoundedPasswordField extends StatefulWidget {
final ValueChanged<String> onChanged;
const RoundedPasswordField({
required this.onChanged,
Key? key,
}) : super(key: key);
#override
_RoundedPasswordFieldState createState() => _RoundedPasswordFieldState();
}
class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
bool _isSecret = true;
#override
Widget build(BuildContext context) {
return TextFieldContainer(
child: TextFormField(
obscureText: _isSecret,
onChanged: widget.onChanged,
decoration: InputDecoration(
hintText: "Password",
icon: Icon(
Icons.lock,
color: DarkTurquoise,
),
suffixIcon: InkWell(
onTap: () => setState(() => _isSecret =
!_isSecret),
child: Icon(!_isSecret
? Icons.visibility
: Icons.visibility_off),
),
),
),
);
}
}

The getter 'hasFocus' was called on null

I have 8 TextFiled and for each I want to prescribe a focus so that the color changes. But I have an error - The getter 'hasFocus' was called on null. How can I fixed that?
class _EditAccountScreenState extends State<EditAccountScreen> {
FocusNode _focusNodeFio;
FocusNode _focusNodeCompany;
...
#override
void initState() {
super.initState();
_focusNodeFio = FocusNode();
_focusNodeCompany = FocusNode();
...
}
#override
void dispose() {
_focusNodeFio.dispose();
_focusNodeCompany.dispose();
...
super.dispose();
}
#override
Widget build(BuildContext context) {
.......
Padding(
child: TextField(
focusNode: _focusNodeFio,
onTap: () {
setState(() {
FocusScope.of(context).requestFocus(_focusNodeFio);
});
},
decoration: InputDecoration(
labelText: 'Contacts',
labelStyle: TextStyle(
color: _focusNodeFio.hasFocus ? Colors.teal[300] : Colors.grey
),
contentPadding:
This is working!
final FocusNode _fNode = FocusNode();
#override
Widget build(BuildContext context) {
return Scaffold(
body: TextField(
focusNode: _fNode,
onTap: () => FocusScope.of(context).requestFocus(_fNode),
decoration: InputDecoration(
labelText: 'Contacts',
labelStyle: TextStyle(color: _fNode.hasFocus ? Colors.teal[300] : Colors.grey),
),
),
);
}