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] lib\add_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,
)
]
)
),
);
}
}
In task_screen.dart create a function like this
void _handleAddTask(String _name)=>setState(()=>tasks.add(Task(name: _name))));
Then modify showModalBottomSheet to look like this
showModalBottomSheet(builder:(context)=>AddTaskScreen(_handleAddTask,"Add task"), context: context);},),);}}
In add_Task_Screen.dart, modify
AddTaskScreen( this.addTaskCallBack, {Key? key}) : super(key: key); to this
AddTaskScreen( this.addTaskCallBack, this.newTaskTitle, {Key? key}) : super(key: key);
create a TextEditingController for your TextField and pass it to it like this
TextField(
autofocus: true,
controller: _textFieldController,
autocorrect: true,
textAlign: TextAlign.center,
onChanged: (newText){
newTaskTitle = newText;
},
),
Finally, in the onPress of Add button, modify it to something like this:
FlatButton(
onPressed: (){
print(newTaskTitle);
addTaskCallBack(_textFieldController.text);
},
child: const Text('Add'),
color: Colors.lightBlueAccent,
)
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:
FlatButton(
onPressed: () {
addTaskCallBack(newTaskTitle);
},
child: const Text('Add'),
color: Colors.lightBlueAccent,
)
Related
I created a checkbox Listtile, where I can click on an Info button to receive further info if neccessary. Therefore I created a main Widget which contains the Listtile widget. When the Info button gets clicked, the detail page opens and reads the specific details from the model class.Up to that point everything works fine.
My leading is a checkbox. If it gets clicked not just one checkbox gets checked, but all of them. how can I write my code, that they arent checked all at the same time automatically?
thank you very much for your help
Kind regards
Here is my code:
//This is my model
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class Info {
String title;
String description;
//String image;
Info(
{required this.title,
required this.description,
// #required this.image
});
}
List<Info> ModelList = [
Info(
title: 'title1',
description: 'description1'
),
Info(
title: 'title2',
description: 'description2'
),
];
//This is the widget
class MainWidget extends StatefulWidget {
const MainWidget({Key? key}) : super(key: key);
#override
State<MainWidget> createState() => _MainWidgetState();
}
class _MainWidgetState extends State<MainWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder
(itemCount: ModelList.length,
itemBuilder: (context,index)
{Info cardname = ModelList[index];
return Card(
child: CheckboxListTile(
tileColor: const Color(0xFF5D6D7E),
shape: RoundedRectangleBorder(
side: const BorderSide (color:Colors.white,width: 2),
borderRadius: BorderRadius.circular(10),
),
contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
value: timeDilation !=1.0,
onChanged: (bool? value) {
setState (() {
timeDilation = value! ? 5.0 : 1.0;
});
},
title: Text(
cardname.title,
style: const TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.w600,
color: Colors.white),
),
//an welcher Stelle die Checkbox ist (links oder rechts)
controlAffinity:
ListTileControlAffinity.leading,
secondary: IconButton(icon: const Icon(Icons.info_outlined,size: 40,color: Colors.orange,), onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context)=> DetailScreen(cardname)
));
},),
)
);
}
,),
)
;
}
}
//Detail screen
//Detail Screen;
class DetailScreen extends StatelessWidget {
final Info cardname ;
const DetailScreen (this.cardname, {super.key});
//const DetailScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customAppBar
((cardname.title),),
body: Padding(
padding: const EdgeInsets.all(8.0) ,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Image.network(
// cardname.imageUrl,
//height: 500,
//),
//
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
cardname.description,
textAlign: TextAlign.justify,
style: const TextStyle(fontSize: 22.0),
),
),
],
),
),
) ,
);
}
}
I tried to put the Item builder in an extra widget and return it into the main widget as shown below, but this didn`t work as well
class SubWidget extends StatefulWidget {
const SubWidget({Key? key}) : super(key: key);
#override
State<SubWidget> createState() => _SubWidgetState();
}
class _SubWidgetState extends State<SubWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder
(itemCount: ModelList.length,
itemBuilder: (context,index)
{Info cardname = ModelList[index];
return MainWidget()
Add variable is isSelected bool for Info class
And after onChanged change value: isSelected = !isSelected
Try this:
class Info {
String title;
String description;
bool isSelected;
//String image;
Info({
required this.title,
required this.description,
required this.isSelected,
// #required this.image
});
}
List<Info> ModelList = [
Info(title: 'title1', description: 'description1', isSelected: false),
Info(title: 'title2', description: 'description2', isSelected: false),
];
//This is the widget
class MainWidget extends StatefulWidget {
const MainWidget({Key? key}) : super(key: key);
#override
State<MainWidget> createState() => _MainWidgetState();
}
class _MainWidgetState extends State<MainWidget> {
double timeDilation = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: ModelList.length,
itemBuilder: (context, index) {
Info cardname = ModelList[index];
return Card(
child: CheckboxListTile(
tileColor: const Color(0xFF5D6D7E),
shape: RoundedRectangleBorder(
side: const BorderSide(color: Colors.white, width: 2),
borderRadius: BorderRadius.circular(10),
),
contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
value: cardname.isSelected,
onChanged: (bool? value) {
setState(() {
cardname.isSelected = !cardname.isSelected;
});
},
title: Text(
cardname.title,
style: const TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.w600,
color: Colors.white),
),
//an welcher Stelle die Checkbox ist (links oder rechts)
controlAffinity: ListTileControlAffinity.leading,
secondary: IconButton(
icon: const Icon(
Icons.info_outlined,
size: 40,
color: Colors.orange,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(cardname),
),
);
},
),
),
);
},
),
);
}
}
How onTap clear TextField in below example?
Note TextField is positioned inside trailing in ListView
trailing: FittedBox(
fit: BoxFit.fill,
child: SizedBox(
height:40, width:100,
child: TextField(
controller: TextEditingController(text: _docData[index].quantity.toString()),
decoration: InputDecoration(
suffix: InkWell(
onTap: () {
setState(() {
});
},
child: Icon(
Icons.clear,
),
)
),
),
),
),
Try this
Create a list of TextEditingController
List<TextEditingController> controllers = List.empty(growable: true);
Then inside ListView.builder, create TextEditingController one by one and add it to controllers list.
Then assign to TextField and clear like this
child: TextField(
controller: controllers[index],
decoration: InputDecoration(
suffix: InkWell(
onTap: () {
setState(() {
controllers[index].clear();
});
},
child: Icon(
Icons.clear,
),
)
),
),
When we call the function:
setState(() {
});
The whole widget rebuilds hence your TextEditingController is initialized again so the text inside is reset to default which is empty
Full Code
1)First Screen
import 'package:flutter/material.dart';
import 'home_page.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyCustomForm(),
);
}
}
2)Second Screen
import 'package:flutter/material.dart';
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
#override
State<MyCustomForm> createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
TextEditingController _controller =TextEditingController();
#override
Widget build(BuildContext context) {
// question: delete textField inside the ListView
return Scaffold(
body: Container(
child: ListView(
children: [
TextField(
onChanged: (value){
_controller.text;
},
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter Name',
suffix: InkWell(
onTap: (){
_controller.clear();
},
child:Icon(Icons.clear),
)
),
)
],
),
),
);
}
}
I am working on a custom dialog called "Alertbox" where the user inserts a name into a textfield and after he pushes the button a function called "addTeam" created a team out of the string.
This is how I created my dialog "Alertbox":
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:trainings_app/config/palette.dart';
class Alertbox extends StatelessWidget {
final Function addTeamFunction;
const Alertbox(this.addTeamFunction);
#override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
elevation: 0,
insetPadding: EdgeInsets.all(10),
child: Center(
child: Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(const Radius.circular(20)),
color: Colors.white,
),
width: 350,
height: 200,
child: Row(
children: [
SizedBox(width: 12),
Expanded(
child: TextField(
textAlign: TextAlign.center,
autofocus: true,
),
),
SizedBox(width: 12),
ElevatedButton(
onPressed: () => addTeamFunction(),
child: const Text('✓'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Palette.orange),
),
),
SizedBox(width: 8),
],
),
),
),
);
}
}
And here I am using it:
void newTeam() {
showDialog<AlertDialog>(
context: context,
builder: (BuildContext context) {
return Alertbox(() {
Navigator.of(context).pop();
});
},
);
}
void addTeam(String name) {
setState(() {
teams.add(name);
});
Navigator.of(context).pop();
sharedPreferences.setStringList('teams', teams);
}
But I can't find a way to parse the input from the textfield into the function "addTeam" where it is needed. Can anyone help me please?
You Should try below code hope its helps you:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Testing',
home: MyCustomForm(),
);
}
}
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: myController,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(myController.text),
);
},
);
},
tooltip: 'Show the value!',
child: const Icon(Icons.add),
),
);
}
}
Your Screen like ->
Use a TextFormField instead of a TexiField widget contained in a Form widget that has a GlobalKey, which will be useful to you during validation!
How to get the value which is already entered on the keyboard?
Uses a TextEditingController or the onSaved method of the TextFormField.
I am trying to make a navigation that scrolls automatically when the mouse cursor moves up or down on it.
When I move the cursor up on the navigation section or the SingleChildScrollView, it should go up and similarly when I move the cursor down, it should go down if you guys get what I mean. Sorry my English isn't very good and I am not particularly good at explaining stuff.
Hope you guys can help me out here.
This is my main.dart file:
import 'package:flutter/material.dart';
import 'package:my_portfolio/pages/homepage.dart';
void main() => runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
));
This is my homepage.dart file
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_portfolio/widgets/nav_llink.dart';
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF2C2A2A),
body: Container(
padding: EdgeInsets.only(left: 120.0, right: 120.0),
child: Row(
children: [
Spacer(),
SingleChildScrollView(
child: Column(
children: [
NavLink(
title: "ABOUT",
onTap: () {},
),
NavLink(
title: "-",
onTap: () {},
),
NavLink(
title: "PROJECTS",
onTap: () {},
),
NavLink(
title: "-",
onTap: () {},
),
NavLink(
title: "CONTACT",
onTap: () {},
),
],
),
),
],
),
),
);
}
}
and finally this are the link "button"
import 'package:flutter/material.dart';
import 'package:flutter/src/gestures/events.dart';
class NavLink extends StatefulWidget {
final String title;
final Function onTap;
Color color = Color(0xFF707070);
int position;
NavLink({ #required this.title, #required this.onTap });
#override
_NavLinkState createState() => _NavLinkState();
}
class _NavLinkState extends State<NavLink> {
#override
Widget build(BuildContext context) {
return RotatedBox(
quarterTurns: 1,
child: Padding(
padding: EdgeInsets.only(right: 80.0, left: 80.0),
child: GestureDetector(
onTap: widget.onTap,
child: MouseRegion(
onHover: updateColor,
onExit: resetColor,
child: Text(
widget.title,
style: TextStyle(
color: widget.color,
fontSize: 180.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
);
}
void updateColor(PointerHoverEvent event) {
setState(() {
widget.color = Colors.white;
widget.position = event.position.dx as int;
});
}
void resetColor(PointerExitEvent event) {
setState(() {
widget.color = Color(0xFF707070);
});
}
}
i have a form which i decided to break into multiple widget for code re- usability. the problem i am having i dont know how to interact with each components. for example, if the main form declare a variable, how do i access that variable in the custom textfield widget which is store in a different dart file.
below is the code i have
form dart file (main.dart)
import 'package:flutter/material.dart';
import 'package:finsec/widget/row_text_input.dart';
import 'package:finsec/widget/text_form_field.dart';
import 'package:finsec/widget/save_button.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/dimens.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/column_text_input.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Simple Interest Calculator App',
home: ThirdFragment(),
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.indigo,
accentColor: Colors.indigoAccent),
));
}
class ThirdFragment extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ThirdFragmentState();
}
}
class _ThirdFragmentState extends State<ThirdFragment> {
var _formKey = GlobalKey<FormState>();
var _currentItemSelected = '';
bool isError = false;
bool isButtonPressed = false;
#override
void initState() {
super.initState();
}
TextEditingController amountController = TextEditingController();
TextEditingController frequencyController = TextEditingController();
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text('Simple Interest Calculator'),
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column (children: [
Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 5.0, left: 15.0, right: 15.0),
child: CustomTextField(textInputType:TextInputType.number,
textController: amountController,
errorMessage:'Enter Income Amount',
labelText:'Income Amount for testing'),
),
RowTextInput(inputName: 'Frequency:',
textInputType: TextInputType.number,
textController: frequencyController,
errorMessage: 'Choose Income Frequency',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Date Paid:',
textInputType: TextInputType.number,
textController: datePaidController,
errorMessage: 'Pick Income Payment Date',
labelText: 'Income Amount for testing'
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save),
onPressed: () => {
setState(() {
if (_formKey.currentState.validate()) {
// amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
//this.displayResult = _calculateTotalReturns();
}
})
},
splashColor: blueGrey,
),
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save_and_continue),
onPressed: () => {},
splashColor: blueGrey,
)
])
]
),
),
}
RowTextInput is a different dart file that contains this code. RowTextInput.dart
import 'package:flutter/material.dart';
import 'package:finsec/utils/hex_color.dart';
class CustomTextField extends StatelessWidget {
CustomTextField({
this.textInputType,
this.textController ,
this.errorMessage,
this.labelText,
});
TextInputType textInputType;
TextEditingController textController;
String errorMessage, labelText;
#override
Widget build(BuildContext context) {
bool isError = false;
return Container(
child: TextFormField(
keyboardType: textInputType,
style: Theme
.of(context)
.textTheme
.title,
controller: textController,
validator: (String value) {
if (value.isEmpty) {
return errorMessage;
}
},
decoration: InputDecoration(
labelStyle: TextStyle(
color: Colors.grey,
fontSize: 16.0
),
contentPadding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), //size of textfield
errorStyle: TextStyle(
color: Colors.red,
fontSize: 15.0
),
border: OutlineInputBorder(
borderSide: BorderSide(width:5.0),
borderRadius: BorderRadius.circular(5.0)
)
)
),
);
}
}
i want to access isError and isButtonPressed variables located in main.dart from RowTextInput.dart and be able to assign values. main.dart should then be able to see those values assign in RowTextInput.dart file.
also,i want to move the MaterialButton button in its own widget file (button.dart) but then i dont know how this dart file will interact with the main.dart file when button is click or to check values of isError and IS button pressed. basically, i am breaking the form into different components (textfield and button) and store them in their own separate file. but i want all the files main.dart, rowintputtext, button.dart(new) to be able to see values of variables in main.dart and change the values. is this possible? is there an easier way?
thanks in advance
If you think about it. In Flutter the Button and RawMaterialButton are already in other files. And the manage to do exactly what you want.
You should create a File mycustomButtons.dart.
In the file you should create a class that will build your Buttons...
But it must has two parameters in it's constructor actionSave actionSaveAndContinue.
You will then create two functions in your main something like:
void _save() {
setState(() {
if (_formKey.currentState.validate()) {
// amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
//this.displayResult = _calculateTotalReturns();
}
})
}
Then you should pass your created functions as parameters:
MyCustomButtons(actionSave: _save, actionSaveAndContinue: _saveAndContinue)
So the button will have all needed information to update your main.dart variables.
The textField is pretty much the same. But you will need pass a validation function and a TextEditingController.
You can see the font of RawnMaterialButton, TextFormField to see how they receive (and pass) data from one class to an other.
I was also looking for breaking a form into multiple classes. This is that I did :
Form
Pass the onSaved function at the form level.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_CustomFormField(
onSaved: (value) => _myModelForm.field1 = value),
),
_CustomFormField2(
onSaved: (value) => _myModelForm.field2 = value),
)
),
RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_formKey.currentState.validate()) {
// Process data.
_formKey.currentState.save();
// Observe if your model form is updated
print(myModelForm.field1);
print(myModelForm.field2)
}
},
child: Text('Submit'),
),
],
),
);
}
_CustomFormField1
The onSaved function will be passed as argument. This class can be either in the same file than the form or in another dedicated file.
class _CustomFormField1 extends StatelessWidget {
final FormFieldSetter<String> onSaved;
//maybe other properties...
_CustomFormField1({
#required this.onSaved,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
// You can keep your validator here
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: onSaved,
),
);
}
}
Like onSaved, you can do the same way for focusNode, onFieldSubmitted, validator if needed in
I hope it will help you and others
There's probably a more elegant way to do it but I am currently experimenting with Singletons. See the code below:
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'dart:async';
class AppModel {
TextEditingController nameController;
TextEditingController surnameController;
StreamController<String> fullnameStreamController;
AppModel() {
nameController = TextEditingController();
surnameController = TextEditingController();
fullnameStreamController = StreamController.broadcast();
}
update() {
String fullname;
if (nameController.text != null && surnameController.text != null) {
fullname = nameController.text + ' ' + surnameController.text;
} else {
fullname = 'Please enter both names';
}
fullnameStreamController.add(fullname);
}
}
GetIt getIt = new GetIt();
final appModel = getIt.get<AppModel>();
void main() {
getIt.registerSingleton<AppModel>(AppModel());
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Singleton Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text;
update() {
setState(() {
});
}
#override
void initState() {
text = 'waiting for input';
appModel.fullnameStreamController.stream.listen((data) {
text = data;
update();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amberAccent),
child: Column(
children: <Widget> [
Card(
color: Colors.white,
child: Text('Name'),
),
Card(
color: Colors.yellow,
child: NameTextField()
),
Divider(),
Card(
color: Colors.white,
child: Text('Surname'),
),
Card(
color: Colors.yellow,
child: SurnameTextField()
),
OkButton(),
Card(
color: Colors.white,
child: Text('Full name'),
),
Card(
color: Colors.orange,
child: FullnameText(text),
),
],
),
),
);
}
}
class NameTextField extends StatefulWidget {
NameTextField({Key key}) : super(key: key);
_NameTextFieldState createState() => _NameTextFieldState();
}
class _NameTextFieldState extends State<NameTextField> {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: appModel.nameController,
),
);
}
}
class SurnameTextField extends StatefulWidget {
SurnameTextField({Key key}) : super(key: key);
_SurnameTextFieldState createState() => _SurnameTextFieldState();
}
class _SurnameTextFieldState extends State<SurnameTextField> {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: appModel.surnameController,
),
);
}
}
class FullnameText extends StatefulWidget {
FullnameText(this.text,{Key key}) : super(key: key);
final String text;
_FullnameTextState createState() => _FullnameTextState();
}
class _FullnameTextState extends State<FullnameText> {
#override
Widget build(BuildContext context) {
return Container(
child: Text(widget.text),
);
}
}
class OkButton extends StatefulWidget {
OkButton({Key key}) : super(key: key);
_OkButtonState createState() => _OkButtonState();
}
class _OkButtonState extends State<OkButton> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white10,
child: RaisedButton(
color: Colors.white,
child: Icon(Icons.check),
onPressed: () {appModel.update();},
),
);
}
}
Check how I use the three controllers in the update function of the AppModel class.
CustomTextFields must extends parent(widget where is form) in this case it is ThirdFragment
class CustomTextField extends ThirdFragment{
CustomTextField({
this.textInputType,
this.textController,
this.errorMessage,
this.labelText,
});