I want to take user input from the textfield widget
and assign in title
variable as in this code
import 'package:flutter/material.dart';
class AddTaskScreen extends StatelessWidget {
final Function callBack; // function
AddTaskScreen({required this.callBack});
@override
Widget build(BuildContext context) {
String title; // declaring the variable
return Container(
height: 350,
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 24,
),
),
SizedBox(
height: 20,
),
TextField(
textAlign: TextAlign.center,
autofocus: false,
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
onChanged: (value) {
title = value; // taking the user input
},
decoration: InputDecoration(
focusColor: Colors.lightBlueAccent,
hintText: 'Type a Task',
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 12,
),
),
),
SizedBox(
height: 20,
),
TextButton(
onPressed: () {
callBack(title); // error
},
style: TextButton.styleFrom(
backgroundColor: Colors.lightBlueAccent,
),
child: Text(
'Add',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
],
),
),
);
}
}
as you can see there is a function callBack
variable. it has the String
parameter when I pass title
in this function it gives me a warning.
here is the code for the callBack when will send this information.
import 'package:flutter/material.dart';
import 'package:todoey/models/Task.dart';
import 'package:todoey/screens/add_task_screen.dart';
import 'package:todoey/screens/bottom_section.dart';
import 'package:todoey/screens/top_section.dart';
class TasksScreen extends StatefulWidget {
@override
State<TasksScreen> createState() => _TasksScreenState();
}
class _TasksScreenState extends State<TasksScreen> {
List<Task> tasks = [];
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: AddTaskScreen(
callBack: (String taskTitle) {
setState(() {
print(taskTitle);
tasks.add(
Task(
name: taskTitle,
),
);
});
Navigator.pop(context);
},
).build(context),
),
),
);
},
child: Icon(
Icons.add,
color: Colors.white,
size: 35,
),
elevation: 5,
backgroundColor: Colors.lightBlueAccent,
),
backgroundColor: Colors.lightBlueAccent,
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TopSection(),
SizedBox(
height: 30,
),
BottomSection(tasks: tasks),
],
),
),
);
}
}
for the main class, here is the code.
import 'package:flutter/material.dart';
import 'package:todoey/screens/task_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: TasksScreen(),
);
}
}
CodePudding user response:
In flutter, you want to store mutable objects (such as your title
) in a State
. This is because the build function can theoretically be called many times, you have no control over it. Therefore, storing the variable in the State
of an object allows you to keep it "alive" while build
is called many times.
Here is your example, adapted to work as intended:
import 'package:flutter/material.dart';
class AddTaskScreen extends StatefulWidget {
final Function callBack; // function
AddTaskScreen({required this.callBack});
@override
State<AddTaskScreen> createState() => _AddTaskScreenState();
}
class _AddTaskScreenState extends State<AddTaskScreen> {
/// Declare title in the state, so that its a long lived object
var title = ""; // Initialize it (likely as empty)
@override
Widget build(BuildContext context) {
return Container(
height: 350,
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Add Task',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 24,
),
),
SizedBox(
height: 20,
),
TextField(
textAlign: TextAlign.center,
autofocus: false,
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
onChanged: (value) {
title = value; // taking the user input
},
decoration: InputDecoration(
focusColor: Colors.lightBlueAccent,
hintText: 'Type a Task',
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 12,
),
),
),
SizedBox(
height: 20,
),
TextButton(
onPressed: () {
widget.callBack(title); // error
},
style: TextButton.styleFrom(
backgroundColor: Colors.lightBlueAccent,
),
child: Text(
'Add',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
],
),
),
);
}
}
CodePudding user response:
So you are using a stateless widget and so you onChanged
function will not work because the state of a stateless widget will not change to render the new value of the title, so you could change it to a stateful widget to see the effect.