How to create segemented slider button like microsoft outlook - flutter

My goal is to have a segmented slider button from Microsoft outlook android
Did anyone know some package to achieve this?

I think you can create using these two slutions
1)Using the CupertinoSlidingSegmentedControl widget.
2)using custom stateful widgets
1)Using the CupertinoSlidingSegmentedControl widget
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
int segmentedControlGroupValue = 0;
final Map<int, Widget> myTabs = const <int, Widget>{
0: Text("Focused"),
1: Text("Other")
};
#override
Widget build(BuildContext context) {
return CupertinoSlidingSegmentedControl(
groupValue: segmentedControlGroupValue,
children: myTabs,
thumbColor:Colors.blueAccent,
onValueChanged: (i) {
setState(() {
segmentedControlGroupValue = int.parse(i.toString());
});
});
}
}
2)Using custom stateful widgets
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
bool _forcused = true;
bool _other = false;
#override
Widget build(BuildContext context) {
return Container(
width: 200,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
color:Colors.grey,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Row(children: [
Expanded(
child: TextButton(
onPressed: () {
setState(() {
_forcused = true;
_other = false;
});
},
child: Text("Focused",style:TextStyle(color:Colors.black)),
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: BorderSide(color: Colors.grey))
),
backgroundColor: MaterialStateProperty.all(_forcused
? Colors.blueAccent
: Colors.grey)
)
)),
Expanded(
child: TextButton(
onPressed: () {
setState(() {
_other = true;
_forcused = false;
});
},
child: Text("Other",style:TextStyle(color:Colors.black)),
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: BorderSide(color: Colors.grey))
),
backgroundColor: MaterialStateProperty.all(_other
? Colors.blueAccent
: Colors.grey)
)
)),
]));
}
}

You probably want to checkout the CupertinoSlidingSegmentedControl widget .

Related

setState() or markNeedsBuild() called during build in Flutter

in my Todo App list, I'm trying to make the global state in my task list view but I'm facing some issues. I'm using StatefulWidget and StatelessWidget. In StatelessWidget Checkbox onChanged I want to toggle the Checkbox value and comes from the parent Widget but it's showing some setState() build issue Please have a look If you can.
tasks_lists.dart
import 'package:flutter/material.dart';
class TasksList extends StatefulWidget {
const TasksList({super.key});
#override
State<TasksList> createState() => _TasksListState();
}
class _TasksListState extends State<TasksList> {
bool isChecked = false;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(
'List 1',
style: TextStyle(
color: Colors.black,
decoration:
isChecked ? TextDecoration.lineThrough : TextDecoration.none,
),
),
trailing: TaskCheckbox(
checkBoxState: isChecked,
toggleCheckboxState: (bool checkedBoxState) {
setState(
() {
isChecked = checkedBoxState;
},
);
},
),
);
}
}
class TaskCheckbox extends StatelessWidget {
final bool checkBoxState;
final Function? toggleCheckboxState;
const TaskCheckbox({
super.key,
required this.checkBoxState,
this.toggleCheckboxState,
});
#override
Widget build(BuildContext context) {
return Checkbox(
value: checkBoxState,
onChanged: toggleCheckboxState!(checkBoxState),
activeColor: Colors.lightBlueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2.0),
),
side: MaterialStateBorderSide.resolveWith(
(states) => BorderSide(
width: 2.0,
color: Colors.black,
),
),
);
}
}
This means that the function is called during build,
onChanged: toggleCheckboxState!(checkBoxState),
while this calls the function when Checkbox is tapped.
onChanged: (checkBoxState) => toggleCheckboxState!(checkBoxState),
Take a look of Introduction to widgets.
Your toggleCheckboxState function call during building the UI, so you need to put it inside addPostFrameCallback so it run after UI builds, like this:
toggleCheckboxState: (bool checkedBoxState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(
() {
isChecked = checkedBoxState;
},
);
});
},
You are changing value/state so you have to make TaskCheckbox a Stateful widget.
onChange is a Fuction(bool). try to change TaskCheckbox to this:
class TaskCheckbox extends StatelessWidget {
final bool checkBoxState;
final Function(bool)? toggleCheckboxState;
const TaskCheckbox({
super.key,
required this.checkBoxState,
this.toggleCheckboxState,
});
#override
Widget build(BuildContext context) {
return Checkbox(
value: checkBoxState,
onChanged: toggleCheckboxState!,
activeColor: Colors.lightBlueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(2.0),
),
side: MaterialStateBorderSide.resolveWith(
(states) => BorderSide(
width: 2.0,
color: Colors.black,
),
),
);
}
}

how to call using rawchip widget

Basically, I have define a list of array but how to call the list on the label. can someone help me
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
color: AppColor.white,
width: MediaQuery.of(context).size.width,
child: RawChip(
showCheckmark: false,
label: Text(widget.list,
style: TextStyle(
color: isSelected ? Colors.black : const Color.fromARGB(255, 45, 110, 162),
fontFamily: 'Poppins'
),),
backgroundColor: isSelected ? Colors.white : const Color.fromARGB(255, 200, 222, 255),
shape: const StadiumBorder(
side: BorderSide(color: Colors.transparent)),
//selectedColor: Colors.red,
selected: isSelected,
onPressed: (){
setState(() {
isSelected = isSelected ? false : true;
});
},
widget.variableName is used to refer top level widget(StatefulWidget ). To get data within state class, just use local
class MyWidget extends StatefulWidget {
final int widgetData;
const MyWidget({
Key? key,
required this.widgetData,
}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final int stateData = 3;
late int makingLocal;
#override
void initState() {
super.initState();
makingLocal = widget.widgetData;
}
#override
Widget build(BuildContext context) {
...
}
}
in your case it will be just list but.
Container(
child: Column(children: list),
),

Flutter: I can't update Listview.builder

I want to add an item to my list the easiest way, but it doesn't change somehow. It must be simple, but somehow I cannot update my list.
If the whole project is needed to solve this problem, I can share the GitHub link. This project is Angela Yu's flutter course last project on Udemy.
This is my add_task screen:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:todoey/model/task.dart';
import 'package:todoey/model/task_bank.dart';
class AddTaskScreen extends StatefulWidget {
const AddTaskScreen({Key? key}) : super(key: key);
static const data = "Add Task";
static const data2 = "Add";
#override
State<AddTaskScreen> createState() => _AddTaskScreenState();
}
class _AddTaskScreenState extends State<AddTaskScreen> {
TextEditingController textEditingController = TextEditingController();
TaskBank taskBank = TaskBank();
String newTaskText = "";
void addItem() {
setState(() {
taskBank.allTasks.add(
Task(
text: newTaskText,
isDone: false,
),
);
textEditingController.clear();
});
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Container(
color: const Color(0xFF757575),
child: Container(
padding: const EdgeInsets.all(20),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
child: Column(
children: [
const Text(
AddTaskScreen.data,
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 30.0,
),
),
TextField(
controller: textEditingController,
autofocus: true,
textAlign: TextAlign.center,
onChanged: (newText) {
newTaskText = newText;
},
),
const SizedBox(height: 10),
CupertinoButton(
child: const Text(AddTaskScreen.data2),
onPressed: () {
addItem();
},
color: Colors.lightBlueAccent,
)
],
),
),
);
}
}
This is listview
import 'package:flutter/material.dart';
import 'package:todoey/model/task_bank.dart';
class TasksListView extends StatefulWidget {
const TasksListView({
Key? key,
}) : super(key: key);
#override
State<TasksListView> createState() => _TasksListViewState();
}
class _TasksListViewState extends State<TasksListView> {
TaskBank taskBank = TaskBank();
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: ListView.builder(
itemCount: taskBank.allTasks.length,
itemBuilder: (context, index) {
bool isChecked = taskBank.allTasks[index].isDone;
return ListTile(
title: Text(taskBank.allTasks[index].text),
trailing: Checkbox(
checkColor: Colors.lightBlueAccent,
value: isChecked,
onChanged: (newVlue) {
setState(() {
isChecked
? isChecked = taskBank.taskDidntDone(index)
: isChecked = taskBank.taskDone(index);
});
print(taskBank.allTasks.length);
},
),
);
},
),
);
}
}
And these are my models.
class Task {
String text;
bool isDone;
Task({required this.text, this.isDone = false});
}
import 'package:todoey/model/task.dart';
class TaskBank {
List<Task> allTasks = [
Task(
text: "Complete to Listview Challange",
isDone: false,
),
Task(
text: "Complate to Udemy Course",
isDone: false,
),
];
bool taskDone(int index) {
return allTasks[index].isDone = true;
}
bool taskDidntDone(int index) {
return allTasks[index].isDone = false;
}
}
The issue is here TasksListView is on separate context and Ui is not getting updated. A simple solution will be passing TaskBank on TasksListView. I will encourage you to look on state-management.
Run on dartPad
class TasksListView extends StatefulWidget {
final TaskBank taskBank;
const TasksListView({
Key? key,
required this.taskBank,
}) : super(key: key);
#override
State<TasksListView> createState() => _TasksListViewState();
}
class _TasksListViewState extends State<TasksListView> {
late TaskBank taskBank;
#override
void initState() {
super.initState();
taskBank = widget.taskBank;
}

How manage state of different widgets in ListView flutter?

I am building a Flutter App where a List is shown using ListView. Which returns a ListTile with User Information. The ListTile contains a leading, title and subtitle with trailing set as a ElevatedButton.
Here's how it looks like:
I want to tap on the 'Invite Button' and change its color, text, and subtitle of the ListTile
After tapping, it should look like this.
How can I do this? Here's the code that I wrote. But it's changing the state of every List Item.
class InviteFriends extends StatefulWidget {
const InviteFriends({Key? key}) : super(key: key);
#override
State<InviteFriends> createState() => _InviteFriendsState();
}
class _InviteFriendsState extends State<InviteFriends> {
bool isSelected = false;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
}
UI Under ListView.builder:
ListTile(
title: const Text('Haris'),
subtitle: const Text(
isSelected ? 'Invitation Sent' : 'Not Invited Yet',
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
_userProfile!.profilePhoto.toString(),
),
),
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: isSelected ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: const Text(
isSelected ? 'Invited': 'Invite',
),
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
),
);
I also tried Keys here in ListTile by using ValueKey(index) but it didn't work either. What should I do? Thanks
Bring out Tile as a separate StatefulWidget so that each has its own state.
Do not modify State List.builder.
And you use one isSelected field for all Tile, and you will all refer to this condition.
Please provide more code and I can help. So that I understand the full picture
You need create different class for listtiles. Do as follows:
ListView.builder(
itemCount: 3,
shrinkWrap: true,
itemBuilder: (ctx, i) {
return MyListItems();
}))
then MyListItems.
class MyListItems extends StatefulWidget {
#override
MyListState createState() => MyListState();
}
class MyListState extends State<MyListItems> {
bool isSelected = false;
#override
Widget build(BuildContext context) {
return ListTile(
title: const Text('Haris'),
subtitle: Text(
isSelected ? "Invitation Sent" : 'Not Invited Yet',
),
leading: const CircleAvatar(
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQYtfZRhbGQtq2BapB2MXJfWIO2QriO5Wx3qQ&usqp=CAU'),
),
// use your image here
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: isSelected ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: Text(
isSelected ? 'Invited' : 'Invite',
),
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
),
);
}}
return ListView.builder(
itemCount: itemCount.length
itemBuilder: (BuildContext context, int index) {
return Friend(
//arg if available
);
});
class Friend extends StatefulWidget {
const Friend({Key? key}) : super(key: key);
#override
_FriendState createState() => _FriendState();
}
class _FriendState extends State<Friend> {
bool isSelected = false;
#override
Widget build(BuildContext context) {
//put ListTile detail here
return Row(
children: [
FlatButton(//deprecated but other buttons work
key: PageStorageKey('random num'),//if you are interested in keeping the state of the button while navigating
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
child: Text(isSelected ? "INVITED" : "INVITE"))
],
);
}
}
You create a list say "i" (variable) to know the state of each tile and initilze all with false. On tap change there state to true.
final List<bool> selected = List.generate(20, (i) => false);
Pass the List "i" to the listview.builder like:-
itemBuilder: (BuildContext context, i)
See the full code
import 'package:flutter/material.dart';
class InviteFriends extends StatefulWidget {
const InviteFriends({Key? key}) : super(key: key);
#override
State<InviteFriends> createState() => _InviteFriendsState();
}
class _InviteFriendsState extends State<InviteFriends> {
bool isSelected = false;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
final List<bool> selected = List.generate(20, (i) => false);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 60),
child: ListView.builder(
// itemCount: i,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: const Text('Haris'),
subtitle: Text(
selected[i] ? 'Invitation Sent' : 'Not Invited Yet',
),
leading: const CircleAvatar(
backgroundImage: AssetImage('assets/profile.gif'),
),
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: selected[i] ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: Text(
selected[i] ? 'Invited' : 'Invite',
),
onPressed: () {
setState(() => selected[i] = !selected[i]);
// setState(() {
// isSelected = !isSelected;
// });
}),
);
}),
),
);
}
}
Thank you
Output

break a form into multiple widget and interact with those widget in flutter

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,
});