I cant even print a nullable value - flutter

basically the problem is clear :
here is my code :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class AddTaskScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
late String newTaskTitle;
return Container(
color: Color(0xFF757575),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.limeAccent[400],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.brown[900]),
),
SizedBox(
height: 12,
),
TextField(
onChanged: (newText) {
newTaskTitle = newText;
},
autocorrect: false,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.brown[800]!,
width: 2,
),
borderRadius: BorderRadius.circular(30),
),
hintText: 'Type Your Task ...',
labelStyle: TextStyle(
color: Colors.green[900],
),
helperStyle: TextStyle(
color: Colors.brown[900],
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(60),
borderSide: BorderSide(
color: Colors.brown[900]!,
width: 2,
),
),
),
),
SizedBox(
height: 12,
),
ElevatedButton(
onPressed: () {
// Provider.of<TaskData>(context, listen: false)
// .addTask(newTaskTitle);
// Navigator.pop(context);
print(newTaskTitle);
// Provider.of<TaskData>(context, listen: false)
// .addTask(newTaskTitle);
// Navigator.pop(context);
},
child: Text(
'Add',
style: TextStyle(color: Colors.brown[900]),
),
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith(
(states) => Colors.lightGreen),
elevation: MaterialStateProperty.resolveWith((states) => 6),
shadowColor:
MaterialStateColor.resolveWith((states) => Colors.green),
minimumSize: MaterialStateProperty.resolveWith(
(states) => Size.square(40.67)),
),
),
],
),
),
);
}
}
please help me ...at this stage I just want to print the value that the user enters in the text field in the console ...but it gives me error :
LateInitializationError: Local 'newTaskTitle' has not been initialized.
i have also changed it to a stateful widget to check if it works with setstate but it didnt ..
i also made it nullable like this => String? newTaskTitle; and Ofcourse it made to change a lot of things but at last the null value was passed ...there is a problem whithin the onChange callback of the textfield that doesnt assign the new value of user input to the variable i have created ...
How can I fixe this problem ?

change
late String newTaskTitle;
to
ValueNotifier<String> newTaskTitle = ValueNotifier("");
and put ElevatedButton inside ValueListenableBuilder
like this
ValueListenableBuilder<String>(
listenable : newTaskTitle,
builder : (ctx,taskt,_){
return ElevatedButton(
onPressed : taskt.isEmpty ? null : (){
// put you logic
}
.....
);
}
);
change onChanged of textField like this
onChanged: (newText) {
newTaskTitle.value = newText;
},

Related

How to get data in a Flutter-ListView?

I'm building a form for shipping and am able to add as many items as possible. (Adding a Widget in a ListView every time a button is pressed)
My question is, once the form widgets are created and filled, how do I get the information from each TextFormField in each Widget?
Once the information is retrieved I will send it to Firebase.
Here's the code I Have:
import 'package:flutter/material.dart';
import 'package:flutter_login_test/helpers/constants.dart';
class AddItemsToRequest extends StatefulWidget {
const AddItemsToRequest({Key? key}) : super(key: key);
#override
State<AddItemsToRequest> createState() => _AddItemsToRequestState();
}
class _AddItemsToRequestState extends State<AddItemsToRequest> {
List<TextEditingController> controllers = [];
List<Widget> fields = [];
RegExp regExp = RegExp('[aA-zZ]');
int quantity = 0;
double weight = 0;
double height = 0;
Widget itemForm() {
return Column(children: [
Container(
decoration:
BoxDecoration(color: grey, border: Border.all(color: black)),
width: double.infinity,
child: const Center(
child: Text('Package details',
style: TextStyle(
fontWeight: FontWeight.bold,
backgroundColor: grey,
fontSize: 24)),
)),
Row(
children: [
Flexible(
child: TextFormField(
onChanged: (value) {
quantity = value as int;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || value is int
? 'Quantity cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Quantity : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
weight = value as double;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || regExp.hasMatch(value)
? 'Weight cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Weight : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
height = value;
},
validator: (value) => value!.isEmpty ? 'Height cannot be empty' : null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Height : "),
),
),
],
),
]);
}
Widget _addTile() {
return ElevatedButton(
child: const Icon(Icons.add),
onPressed: () async {
final controller = TextEditingController();
final field = itemForm();
setState(() {
controllers.add(controller);
fields.add(field);
});
});
}
Widget _listView() {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: fields.length,
itemBuilder: (context, index) {
final item = fields[index];
return Dismissible(
key: ObjectKey(item),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
fields.removeAt(index);
});
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Package removed')));
},
background: Container(
color: const Color.fromARGB(255, 210, 31, 19),
child: const Center(
child: Text(
'Remove ',
style: TextStyle(
color: white, fontWeight: FontWeight.bold, fontSize: 32),
),
)),
child: Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: fields[index],
),
);
},
);
}
Widget _okButton() {
return ElevatedButton(
onPressed: () {
for (var element in fields) {
print(quantity);
}
Navigator.of(context).pop();
print('ok');
},
child: const Text("OK"),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: blue),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(child: _addTile()),
SizedBox(
height: MediaQuery.of(context).size.height - 200,
child: _listView()),
Flexible(child: _okButton()),
],
),
);
}
}
I think you are expecting this answer. iterate your list of texteditingcontroller and get the text stored in that controllers one by one.
for (int i = 0; i < controllers.length; i++) {
var data = controllers[i].text;
//print or add data to any other list and insert to another list and save to database
}

Separate suffixIcon for password visibility

How to separate suffixIcon for password visibility? If I press icon on field password it also does the same thing on field confirm password.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isObsecure = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Text Form Field'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Confirm Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
],
),
),
),
);
}
}
you have to define 2 flags. 1 for password visibility and 1 for confirm:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isObsecure = false;
bool isConfirmObsecure = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Text Form Field'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
TextFormField(
obscureText: isConfirmObsecure,
decoration: InputDecoration(
hintText: 'Confirm Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isConfirmObsecure = !isConfirmObsecure;
});
},
icon: Icon(
isConfirmObsecure
? Icons.visibility_off
: Icons.visibility,
),
),
),
),
],
),
),
),
);
}
}
///You can use the provider also to hide and visible the password icon. Hope this will work for you.
////This is my forgot password screen
import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';
import 'package:provider/provider.dart';
import 'package:traveling/Provider/common/ObscureTextState.dart';
import 'package:traveling/helpers/AppColors.dart';
import 'package:traveling/helpers/AppStrings.dart';
import 'package:traveling/screens/Employee/home/BottomNavBar.dart';
class ForgotPasswordA extends StatefulWidget {
#override
_ForgotPasswordAState createState() => _ForgotPasswordAState();
}
class _ForgotPasswordAState extends State<ForgotPasswordA> {
/// These variables are used for getting screen height and width
double? _height;
double? _width;
///controllers are used to get text which user enter in TextFiled
TextEditingController confirmPasswordController = TextEditingController();
TextEditingController passwordController = TextEditingController();
GlobalKey<FormState> _formkey = GlobalKey();
String? confirmPassword, password;
#override
void initState() {
// TODO: implement initState
super.initState();
}
///this widget is the main widget and it is used for building a UI in the app
#override
Widget build(BuildContext context) {
_height = MediaQuery.of(context).size.height;
_width = MediaQuery.of(context).size.width;
return Material(
child: Scaffold(
backgroundColor: AppColors.white,
body:Consumer<LoginProvider>(
builder:(context, obs, child) {
///Consumer is used to get value from the loginProvider class
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(
height: _height,
width: _width,
margin: EdgeInsets.only(top: 70),
padding: EdgeInsets.only(bottom: 5),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height: _height! / 22),
appText(),
SizedBox(height: _height! / 18),
Container(
width: _width! * .85,
child: Form(
///define global key for validation
key: _formkey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: <Widget>[
SizedBox(height: _height! / 50),
TextFormField(
controller: passwordController,
validator: (value) {
if (value!.isEmpty) {
return "Please Enter Password!";
} else if (value.length < 6) {
return "Please Enter more than 6 digit .";
} else {
return null;
}
},
obscureText:
Provider.of<LoginProvider>(context, listen: false)
.isTrue,
keyboardType: TextInputType.emailAddress,
autofillHints: [AutofillHints.email],
cursorColor: AppColors.black,
style: TextStyle(
color: Color(0xff919AAA),
),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
floatingLabelBehavior: FloatingLabelBehavior.never,
suffixIcon: IconButton(
onPressed: () {
Provider.of<LoginProvider>(context, listen: false)
.toggleObs();
},
icon: Provider.of<LoginProvider>(context,
listen: false)
.switchObsIcon,
),
labelText: 'Password',
errorStyle: TextStyle(color: AppColors.red),
hintStyle: TextStyle(
color: Color(0xff919AAA),
),
),
),
//passwordTextFormField(),
SizedBox(height: _height! / 30.0),
///password visibility handle by provider state management
TextFormField(
controller: confirmPasswordController,
validator: (value) {
if (value!.isEmpty) {
return "Please Enter Password!";
} else if (value.length < 6) {
return "Please Enter more than 6 digit .";
} else {
return null;
}
},
obscureText:
Provider.of<LoginProvider>(context, listen: false)
.isConfirmPassword,
keyboardType: TextInputType.emailAddress,
autofillHints: [AutofillHints.email],
cursorColor: AppColors.black,
style: TextStyle(
color: Color(0xff919AAA),
),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
floatingLabelBehavior: FloatingLabelBehavior.never,
suffixIcon: IconButton(
onPressed: () {
Provider.of<LoginProvider>(context, listen: false)
.toggleObsData();
},
icon: Provider.of<LoginProvider>(context,
listen: false)
.switchObsIcons,
),
labelText: 'Confirm Password',
errorStyle: TextStyle(color: AppColors.red),
hintStyle: TextStyle(
color: Color(0xff919AAA),
),
),
),
],
),
),
),
SizedBox(height: _height! / 28),
SizedBox(height: _height! / 22),
submitButton(),
SizedBox(height: _height! / 35),
],
),
),
),
);}
),
),
);
}
///app-text Widget is used for app logo and icon in top side
Widget appText() {
return Container(
width: _width! * 0.90,
child: Column(
children: <Widget>[
Image.asset(
"assets/traveling-text-icon.png",
height: 60,
),
SizedBox(
height: 5,
),
],
),
);
}
///for validation we used a submit button
Widget submitButton() {
return Card(
elevation: 20.0,
shadowColor: Colors.blue[100],
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
child: Container(
height: 60,
width: _width! * .85,
decoration: BoxDecoration(
// boxShadow: [BoxShadow(color: AppColors.grey, blurRadius: 20.0)],
borderRadius: BorderRadius.circular(20.0),
gradient: LinearGradient(colors: [
AppColors.blue,
Colors.blue.shade900,
])),
child: MaterialButton(
onPressed: () {
if(passwordController.text==confirmPasswordController.text){
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => EmployeeBottomNavBar()));}
else{
print("password did not match");
}
},
child: Text(
AppStrings.submit,
style: TextStyle(
color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold),
),
),
),
);
}
}
////provider class
import 'package:flutter/material.dart';
import 'package:traveling/helpers/AppColors.dart';
class LoginProvider extends ChangeNotifier {
bool _isTrue = true;
bool _isConfirmPassword = true;
bool get isTrue => _isTrue;
bool get isConfirmPassword => _isConfirmPassword;
get switchObsIcons {
return _isConfirmPassword ? Icon(Icons.visibility_off,color: AppColors.textFieldTextColor,) : Icon(Icons.visibility,color: AppColors.textFieldTextColor,);
}
get switchObsIcon {
return _isTrue ? Icon(Icons.visibility_off,color: AppColors.textFieldTextColor,) : Icon(Icons.visibility,color: AppColors.textFieldTextColor,);
}
void toggleObsData() {
_isConfirmPassword = !_isConfirmPassword;
notifyListeners();
}
void toggleObs() {
_isTrue = !_isTrue;
notifyListeners();
}
}

How to check time is after 3 min from a time or not in Flutter | Dart

I want to edit a form only after 3 minutes from the last edit. I am getting a last update time as string from api when loading that form for eg: 11:53:09. So i want to show submit form button only after 3 minutes from the last update time. Otherwise i want to show a Text that form can be edited after 3 minutes. How to acheive this functionality.
Hello there you can achieve this by using simple logic, here is the basic code for this implementation:
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
static const String id = 'login_screen';
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final formKey = GlobalKey<FormState>();
bool _canSubmit = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: formKey,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextFormField(
onChanged: (value) {},
obscureText: false,
style: TextStyle(
color: Colors.black54,
fontSize: 16.0,
fontWeight: FontWeight.w700),
decoration: InputDecoration(
labelStyle: TextStyle(color: Colors.black54),
focusColor: Colors.black54,
filled: true,
enabledBorder: UnderlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.black54),
),
labelText: "Email"),
validator: (value) {
if (value.isEmpty ||
!RegExp(r'^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(value)) {
return "Enter Correct Email Address";
} else {
return null;
}
},
),
SizedBox(
height: 10.0,
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextFormField(
onChanged: (value) {},
style: TextStyle(
color: Colors.black54,
fontSize: 16.0,
fontWeight: FontWeight.w700),
decoration: InputDecoration(
labelStyle: TextStyle(color: Colors.black54),
focusColor: Colors.black54,
filled: true,
enabledBorder: UnderlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.black54),
),
labelText: "Password"),
validator: (value) {
if (value.isEmpty) {
return "Enter Valid Password";
} else {
return null;
}
},
)
],
),
SizedBox(
height: 10.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
constraints:
BoxConstraints(maxHeight: 36, maxWidth: 36),
icon: Icon(
Icons.lock,
size: 20,
color: Colors.black54,
),
onPressed: _canSubmit
? () {
if (formKey.currentState.validate()) {
FocusManager.instance.primaryFocus
?.unfocus();
submitPressed();
}
}
: null)
]),
],
),
),
],
),
));
}
Future<void> submitPressed() async {
setState(() {
_canSubmit = false;
});
Future.delayed(Duration(minutes: 3), () {
setState(() {
_canSubmit = true;
});
});
}
}
You can parse the last update time to DateTime and compare it with DateTime.now()
updatedTime = 11:53:09
DateFormat format = new DateFormat("hh:mm:ss");
updatedTime = format.format(updatedTime);
in your widget add this
DateTime.now() - updatedTime < 3 ? Text("form can be edited after 3 minutes") : Form()
you can parse you datetime in DateTime.parse() and then you can use it like this
DateTime.now().isAfter(lastEditedDateTime.add(const Duration(minutes: 3)));
in addition to this you can also use future delay to update you button enable variable to update every second.

ValueNotifier<String>#97fe7(go to the gym)

Hi everyone : the problem is simple but i just cant find the solution
here is my code :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todoye_app_angela/models/task_data.dart';
class AddTaskScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
ValueNotifier<String> newTaskTitle = ValueNotifier("");
return Container(
color: Color(0xFF757575),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.limeAccent[400],
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.brown[900]),
),
SizedBox(
height: 12,
),
TextField(
onChanged: (newText) {
newTaskTitle.value = newText;
},
autocorrect: false,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.brown[800]!,
width: 2,
),
borderRadius: BorderRadius.circular(30),
),
hintText: 'Type Your Task ...',
labelStyle: TextStyle(
color: Colors.green[900],
),
helperStyle: TextStyle(
color: Colors.brown[900],
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(60),
borderSide: BorderSide(
color: Colors.brown[900]!,
width: 2,
),
),
),
),
SizedBox(
height: 12,
),
ValueListenableBuilder<String>(
valueListenable: newTaskTitle,
builder: (context, taskt, child) {
return ElevatedButton(
onPressed: taskt.isEmpty
? null
: () {
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.toString());
print(taskt);
Navigator.pop(context);
// Provider.of<TaskData>(context, listen: false)
// .addTask(newTaskTitle);
// Navigator.pop(context);
},
child: Text(
'Add',
style: TextStyle(color: Colors.brown[900]),
),
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith(
(states) => Colors.lightGreen),
elevation: MaterialStateProperty.resolveWith((states) => 6),
shadowColor: MaterialStateColor.resolveWith(
(states) => Colors.green),
minimumSize: MaterialStateProperty.resolveWith(
(states) => Size.square(40.67)),
),
);
},
),
],
),
),
);
}
}
im trying to add some tasks in my todo app . simply the user have to type something in the textfield and this value is passed to the addtask function in my taskdata class to notify the listeners about it . the problem was th newTaskTitle variable is of type ValueNotifier and the value of my input function is a String i tried to solve this problem by adding the toString method here:
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.toString());
but it returns this : ValueNotifier#97fe7(go to the gym) on the screen .. i just want the pure String from user .
please help me solve this problem ...
I appreciate it inadvance.
Your are using ValueNotifier.
Use ValueNotifier.value , newTaskTitle.value in your case to get the String value.
code:
...
...
Provider.of<TaskData>(context, listen: false)
.addTask(newTaskTitle.value);
...

why does printing the text value in here brings up null?

So i'm trying to print out the value that's newTaskTitle when i press the flat button but it always brings up null , although when i print it in the textField it shows correctly , any idea why ?
for example on the onChanged for the text field , i try to print after assigning the newTaskTitle value to the newText , it prints the value
if I then try to print the value on the onPressed in the flat button , it print null .
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:todoey/models/task.dart';
class AddTaskScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
String newTaskTitle;
return Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 30.0,
),
),
TextField(
autofocus: true,
textAlign: TextAlign.center,
onChanged: (newText) {
newTaskTitle = newText;
},
),
SizedBox(
height: 10.0,
),
FlatButton(
color: Colors.lightBlueAccent,
onPressed: () {
//addTaskCallback(newTaskTitle);
print(newTaskTitle);
},
child: Text(
'Add',
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
);
}
}
You need to update the state of the widget.
The widget you are using is stateless, that is, it does not manipulate states, a solution (There are many) is to transform your widget from stateless to stateful.
Then you could use a SetState or ValueNotifier to modify the value.
Example:
import 'package:flutter/material.dart';
class AddTaskScreen extends StatefulWidget {
AddTaskScreen({Key key}) : super(key: key);
#override
_AddTaskScreenState createState() => _AddTaskScreenState();
}
class _AddTaskScreenState extends State<AddTaskScreen> {
String newTaskTitle = '';
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 30.0,
),
),
TextField(
autofocus: true,
textAlign: TextAlign.center,
onChanged: (newText) {
newTaskTitle = newText;
},
),
SizedBox(
height: 10.0,
),
FlatButton(
color: Colors.lightBlueAccent,
onPressed: () {
setState(() {});
},
child: Text(
'Add',
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
);
}
}
You are trying to change the state of stateless widget. Convert your widget to StatefulWidget by clicking on Stateless and then pressing Ctrl + ., select convert to Stateful widget and then test app again.