I am making a List App which a list of items followed by a checkBox .Then there is a floating action button with a plus sign .On click of it u get a bottomSheet .In the bottom sheet you can enter your task to the textField .On clicking on the add button the tasks gets added .
The ui Looks like this
I am not able to access tasks List that is defined in the task_screen.dart from add_taskScreen.dart . I am getting the below error despite importing the required files
error: Undefined name 'tasks'. (undefined_identifier at [todoey_flutter] libadd_task_screen.dart:43)
here is my Code
Main.dart
import 'package:flutter/material.dart';
import 'tasks_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: TaskScreen(),
);
}
}
Task_tile.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TaskTile extends StatelessWidget {
@override
late final bool isChecked ;
late final String taskTitle;
final Function checkBoxCallBack;
TaskTile({required this.isChecked,required this.taskTitle,required this.checkBoxCallBack});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(taskTitle,
style:TextStyle(
decoration: isChecked ? TextDecoration.lineThrough:null
),
),
trailing: Checkbox(
value:isChecked,
activeColor:Colors.lightBlueAccent,
onChanged: (newValue) {//onChanged here if we select the check box the value becomes true else it will become false
checkBoxCallBack(newValue);//widget.toggleCheckBoxState(value);
},
)
);
}
}
Task_list.dart
import 'package:flutter/material.dart';
import 'task_title.dart';
import 'Models/task.dart';
class TaskList extends StatefulWidget {
final List<Task> tasks;
TaskList(this.tasks);
@override
State<TaskList> createState() => _TitleListState();
}
class _TitleListState extends State<TaskList> {
@override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (context,index){//in the listView Builder index is already defined and gets updated by itself
return TaskTile(
taskTitle:widget.tasks[index].name,
isChecked: widget.tasks[index].isDone,
checkBoxCallBack:(bool checkBoxState){
setState((){
widget.tasks[index].toggleDone() ;
});
}
);
},
itemCount: widget.tasks.length,//max no tasks that can fit in the screen ie..how many ever tasks are there on 'tasks' it will build that many
);
}
}
task.dart
import 'package:flutter/material.dart';
class Task{
late final String name;
late bool isDone;
Task
({required this.name,this.isDone=false});//give a default value to isDone
void toggleDone()
{
isDone = !isDone;
}
}
task_Screen.dart
import 'package:flutter/material.dart';
import 'tasks_list.dart';
import 'add_task_screen.dart';
import 'package:todoey_flutter/Models/task.dart';
class TaskScreen extends StatefulWidget {
const TaskScreen({Key? key}) : super(key: key);
@override
State<TaskScreen> createState() => _TaskScreenState();
}
class _TaskScreenState extends State<TaskScreen> {
List<Task> tasks = [
Task(name: 'Buy milk'),
Task(name: 'Buy eggs'),
Task(name: 'Buy bread'),
];
@override
Widget build(BuildContext context) {
return Scaffold(//Scaffold contains everything
backgroundColor: Colors.lightBlueAccent,
body:Column(
children: [
Container(
padding:const EdgeInsets.only(top:60,left:30,right:30,bottom: 30),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:const <Widget>[
CircleAvatar(
child: Icon(
Icons.list,
color: Colors.lightBlueAccent,
size:30.0,
),
backgroundColor:Colors.white,
radius:30,
),
SizedBox(height:10),
Text(
'Todoey',
style:TextStyle(
color:Colors.white,
fontSize: 50,
fontWeight: FontWeight.w700,
)
),
Text('12 Tasks',
style:TextStyle(
color:Colors.white,
fontSize: 18,
)
),
]
),
),
Expanded(
child: Container(//designing the white part of the todoey
padding:const EdgeInsets.symmetric(horizontal: 20),
height:300,
decoration: const BoxDecoration(
color:Colors.white,
borderRadius: BorderRadius.only(
topLeft:Radius.circular(20.0),
topRight:Radius.circular(20.0),
),
),
child: TaskList(tasks),
),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor:Colors.lightBlueAccent,
child: const Icon(
Icons.add,
),
onPressed: (){ //call the bottomSheet in builder
showModalBottomSheet(builder:(context)=>AddTaskScreen(
(newTaskTitle)
{
setState(){
tasks.add(Task(name:newTaskTitle));
}
}), context: context);//to create bottom drawer widget on pressing the button a new pop up appears at the bottom
},
),
);
}
}
add_Task_Screen.dart
import 'package:flutter/material.dart';
import 'task_title.dart';
import 'tasks_list.dart';
import 'tasks_screen.dart';
import 'package:todoey_flutter/Models/task.dart';
class AddTaskScreen extends StatelessWidget {
late String newTaskTitle;
final Function addTaskCallBack;
AddTaskScreen( this.addTaskCallBack, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
//color:const Color(0xff757575),//you cant add color 2 times it will throw an exception
decoration:const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topLeft:Radius.circular(20.0) ,topRight:Radius.circular(20.0)),
),
child:Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children:[
const Center(
child: Text('Add Task',
style: TextStyle(
fontSize:30.0,
color:Colors.lightBlueAccent,
),
),
),
TextField(
autofocus: true,
autocorrect: true,
textAlign: TextAlign.center,
onChanged: (newText){
newTaskTitle = newText;
},
),
FlatButton(
onPressed: (){
print(newTaskTitle);
tasks.add(name:newTaskTitle);//here is the error
},
child: const Text('Add'),
color: Colors.lightBlueAccent,
)
]
)
),
);
}
}
2
Answers
The tasks list does not exist in the child widget. You can access the widget via the callback method you provided.
Refactor your FlatButton to look like this:
In task_screen.dart create a function like this
Then modify
showModalBottomSheet
to look like thisIn
add_Task_Screen.dart
, modifyAddTaskScreen( this.addTaskCallBack, {Key? key}) : super(key: key);
to thiscreate a
TextEditingController
for your TextField and pass it to it like thisFinally, in the onPress of Add button, modify it to something like this: