content vanish every time I restart the app - flutter

I created a page where I can add exercise for my classes and in this page students can create their custom training (it's a gym app), the only problem is that every time the user closes the app all the training is gone.
I leave below my code, I've done some researches and I kind of understood that there is something with SharPreferences but all the tutorial talk about a login page which is not my case.
can you please advise?? I leave my code below, thanks!
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class Custom extends StatefulWidget {
#override
_CustomState createState() => new _CustomState();
}
class _CustomState extends State<Custom> {
int _count = 0;
#override
Widget build(BuildContext context) {
List<Widget> _esercizi = List.generate(_count, (int i) => Esercizi());
bool visible = _count > 0;
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Scaffold(
appBar: AppBar(
title: Text('Scheda personalizzata'),
actions: [
Visibility(
visible: visible,
child: IconButton(
icon: Icon(Icons.remove_rounded),
onPressed: _removeNewEsercizi,
),
),
IconButton(icon: Icon(Icons.add), onPressed: _addNewEsercizi),
],
backgroundColor: Colors.blueGrey,
),
body: LayoutBuilder(builder: (context, constraint) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
height: 700,
child: ListView(
scrollDirection: Axis.vertical,
children: _esercizi,
),
),
//new ContactRow()
],
),
),
);
}),
),
);
}
void _addNewEsercizi() {
setState(() {
_count = _count + 1;
});
}
void _removeNewEsercizi() {
setState(() {
_count = _count - 1;
});
}
}
class Esercizi extends StatefulWidget {
#override
State<StatefulWidget> createState() => _Esercizi();
}
class _Esercizi extends State<Esercizi> {
String dropdownValue = 'Seleziona esercizio';
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DropdownButton<String>(
value: dropdownValue,
style: TextStyle(color: Colors.blueGrey),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>['Seleziona esercizio', 'One', 'Two', 'Three', 'Fo'
'ur', 'Five', 'Six']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
Container(
height: 50,
width: 90,
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
cursorColor: Colors.white,
decoration: InputDecoration(
hintText: 'Time/Reps',
hintStyle: TextStyle(color: Colors.blueGrey),
),
keyboardType: TextInputType.number,
),
),
),
),
],
),
);
}
}

Related

selected dropdown height overflow

so i have this dropdown and the DropdownMenuItem i have ListTile, below is the option result
after i select it the result become like this
Here is my script
Visibility(
visible: _signalEmiten != null,
child: Container(
height: 150.w,
child: FutureBuilder<List<Mt5Model>>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("ERROR PLEASE RE OPEN SCREEN");
}
return snapshot.hasData
? Container(
child: DropdownButtonFormField(
itemHeight: 150.w,
decoration: InputDecoration(
labelText: 'Choose Account',
),
items: snapshot.data
.map<DropdownMenuItem>((Mt5Model item) {
return DropdownMenuItem(
value: item.mt5Id,
child: Container(
padding:
EdgeInsets.symmetric(vertical: 5.w),
width: MediaQuery.of(context).size.width *
.80,
child: ListTile(
dense: true,
//leading: Text(item.mt5Id.toString()),
title: Text("123456"),
subtitle: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text("Account Type : " + "Type 1"),
Text("Equity : \$ " + "XXXX"),
],
),
),
),
);
}).toList(),
onChanged: (value) {
setState(() {
dropDownValue = value;
populateAccount();
});
},
),
)
: Container(
child: Center(
child: Text('Loading...'),
),
);
},
),
),
),
i already trying to increate the height of my container and DropdownButtonFormField height, but still no help. So, how can i fix it ?
Here I tried to solve the issue, you need to wrap the ListTile subtitle with SingleChildScrollView and enable isThreeLine.you can check with the example below.
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: DropDownExample(),
);
}
}
class DropDownExample extends StatefulWidget {
const DropDownExample({Key? key}) : super(key: key);
#override
_DropDownExampleState createState() => _DropDownExampleState();
}
class _DropDownExampleState extends State<DropDownExample> {
String dropDownValue = "rohit";
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: DropdownButtonFormField(
itemHeight: 100,
decoration: const InputDecoration(
labelText: 'Choose Account',
contentPadding: EdgeInsets.symmetric(vertical: 30)),//Fit the content on dropdown selected value
menuMaxHeight: 300,
value: dropDownValue,
isExpanded: true,
isDense: true,
iconSize: 30,
items: ["rohit", "manish"].map<DropdownMenuItem>((item) {
return DropdownMenuItem(
value: item,
child: Container(
width: MediaQuery.of(context).size.width * .80,
child: ListTile(
dense: false,
//leading: Text(item.mt5Id.toString()),
isThreeLine: true, //getting extra height for ListTile
title: Text("123456"),
subtitle: Container(
color: Colors.yellow,
child: SingleChildScrollView( //to solve over flow issues
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Equity : \$ " + item),
Text("Account Type : " + "Type 1"),
],
),
),
),
),
),
);
}).toList(),
onChanged: _te,
)),
);
}
void _te(value) {
setState(() {
dropDownValue = value.toString();
// populateAccount();
});
}
}
I think you need to remove first container
height: 150.w,

Flutter|Updating a ListView

everyone!
I have a HomeScreen, with this code:
return SafeArea(
child: Scaffold(
body: Stack(
children: [
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: Column(children: [
ActiveTaskInfo(
task: tasks.first,
),
const TextWidget(),
Expanded(child: TasksList()),
const SizedBox(height: 80),
]),
),
BottomBarClass(),
],
),
),
);
TasksList() - ListView.
BottomBarClass() - It is a container with a button inside.
If you return the code itself to the main HomeScreen file, everything works, but if you put it in a separate class and when you add a new item to the list (through the button) nothing happens, but if you press Hot Reload, then the new item in the list is displayed.
Code BottomBarClass():
Positioned(
bottom: 0, left: 0,
child: ClipRRect(
borderRadius: const BorderRadius.only(topRight: Radius.circular(30), topLeft: Radius.circular(30)),
child: Container(
height: 80, width: MediaQuery.of(context).size.width,
color: const Color(0xff070417),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(Icons.watch_later, color: Colors.white.withOpacity(0.4)),
IconButton(icon: Icon(Icons.add, color: Colors.white.withOpacity(0.4),), iconSize: 32, onPressed: () async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return TaskAdding();
}));
if (result == true) {
setState(() {
});
}
}),
Icon(Icons.pie_chart_rounded, color: Colors.white.withOpacity(0.4), size: 24,),
],),
),
));
Вот пример GIF: https://gifyu.com/image/Spp1O
TaskAdding():
import 'package:flutter/material.dart';
import '../expansions/task_tags_decorations.dart';
import '../expansions/tasks_data.dart';
class TaskAdding extends StatefulWidget {
const TaskAdding({Key? key}) : super(key: key);
#override
State<TaskAdding> createState() => _TaskAddingState();
}
class _TaskAddingState extends State<TaskAdding> {
late String _addField;
late Widget _selectedValue;
late bool _active;
late int _selectedIndex;
#override
void initState() {
_addField = 'Empty';
_active = false;
_selectedValue = tasks[0].icon;
_selectedIndex = 0;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Add'), backgroundColor: Colors.pink),
body: Column(children: [
Text('Add Task', style: TextStyle(color: Colors.white, fontSize: 24),),
TextField(onChanged: (String value) {
_addField = value;
}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DropdownButton<Widget>(
value: _selectedValue,
onChanged: (newValue) {
setState(() {
_selectedValue = newValue!;
});
},
items: dropdownItems,
),
ElevatedButton(
onPressed: () {
setState(() {
tasks.addAll({
TaskData(
taskName: _addField,
tagOne: _active
? tasks[0].tagOne
: tasks[1].tagOne,
tagTwo: tagTwoContainer[_selectedIndex],
icon: _selectedValue,
taskTime: '00:32:10',
)
});
decorations.addAll({
TaskTagsDecorations(
iconColor: const Color(0xff7012CF))
});
});
Navigator.of(context).pop(true);
},
child: const Text('Add')),
],
),
Center(
child: ListTile(
title: _active
? Center(
child: tasks[0].tagOne,
)
: Center(child: tasks[1].tagOne),
selected: _active,
onTap: () {
setState(() {
_active = !_active;
});
},
),
),
SizedBox(
height: 52,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: tagTwoContainer.length,
itemBuilder: (context, index) {
var tagTwoList = tasks[index].tagTwo;
return SizedBox(
height: MediaQuery.of(context).size.height, width: 160,
child: ListTile(
visualDensity: VisualDensity.compact,
selected: index == _selectedIndex,
selectedTileColor: Colors.indigo.withOpacity(0.6),
title: Align(
alignment: Alignment.topCenter,
child: tagTwoList),
onTap: () {
setState(() {
_selectedIndex = index;
});
},
),
);
}),
),
],),
);
}
List<DropdownMenuItem<Widget>> get dropdownItems {
List<DropdownMenuItem<Widget>> menuItems = [
DropdownMenuItem(
child: const Icon(Icons.free_breakfast),
value: iconCircle[0],
),
DropdownMenuItem(
child: const Icon(Icons.grade_outlined), value: iconCircle[1]),
DropdownMenuItem(child: const Icon(Icons.gamepad), value: iconCircle[2]),
DropdownMenuItem(
child: const Icon(Icons.face_rounded), value: iconCircle[3]),
];
return menuItems;
}
}
You question is not clear. Try to add TasksList()
My solution:
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));

Passing stateless widget from one screen to another screen in Flutter

I am trying to create a form builder, In one screen I want have small container with icon and text with gesture detector, when I tap on the container it should contruct a new DatePicker Widget. I know how to do it in the same screen, but onTap I want construct the Datepicker in another screen.
This is Form Component Class.
class FormComponents extends StatefulWidget {
#override
_FormComponentsState createState() => _FormComponentsState();
}
class _FormComponentsState extends State<FormComponents> {
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
int _count = 0;
final formData = FormWidgetData(widget: DatePicker());
#override
Widget build(BuildContext context) {
List<Widget> datePicker = List.generate(_count, (index) => DatePicker());
return Scaffold(
appBar: AppBar(
title: Text('Form Components'),
),
body: Container(
margin: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
initialValue: {
'date': DateTime.now(),
'accept_terms': false,
},
autovalidate: true,
child: Column(
children: <Widget>[
Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_count = _count + 1;
});
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Date Picker'),
duration: Duration(seconds: 2),
),
);
},
child: Container(
margin: EdgeInsets.all(16.0),
padding: EdgeInsets.all(8.0),
height: 100.0,
width: 120.0,
color: Colors.black,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Icon(
Icons.date_range,
color: Colors.white,
),
Text(
'Date Picker',
style: TextStyle(
color: Colors.white, fontSize: 18.0),
),
],
),
),
);
},
),
Container(
height: 200.0,
margin: EdgeInsets.all(8.0),
child: Expanded(
child: ListView(
children: datePicker,
),
),
),
],
),
),
],
),
),
);
}
}
This is my Date Picker Class
class DatePicker extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: FormBuilderDateTimePicker(
attribute: 'date',
inputType: InputType.date,
format: DateFormat('yyyy-MM-dd'),
decoration: InputDecoration(labelText: 'AppointmentTime'),
),
);
}
}
This is my Form Builder Class, How to do I Construct the above Date Picker class here.
class MyFormBuilder extends StatefulWidget {
final FormWidgetData data;
MyFormBuilder({this.data});
#override
_MyFormBuilderState createState() => _MyFormBuilderState();
}
class _MyFormBuilderState extends State<MyFormBuilder> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Builder'),
),
body: Container(
height: 300.0,
margin: EdgeInsets.all(8.0),
child: Expanded(
child: ListView(
children: <Widget>[],
),
),
),
);
}
}

Navigate Flat Button to Another Screen from Bottom Navigation Bar Item current Index using Provider

I created a provider using the provider package that tells if an item on the BottomNavigationBar is pressed, so that the page displayed matches the item from the BottomNavigationBar on the body properties of the Scaffold. I've made a screen with TextFormField and FlatButton on the first BottomNavigationBar item. what I want to do is, I want to add all the data that has been entered in TextFromField to the third screen item from the BottomNavigationBar that I have created, and then display the third item page from the BottomNavigationBar that was added to the data through FlatButton on first screen.
I have been searching for solutions to this problem for days, but I also haven't found the answer.
My provider for BottomNavigationBar
import 'package:flutter/material.dart';
class Index with ChangeNotifier {
int _currentindex = 0;
get currentindex => _currentindex;
set currentindex(int index){
_currentindex = index;
notifyListeners();
}
}
My Scaffold
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
var currentTab = [
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
];
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
body: currentTab[provider.currentindex],
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
provider.currentindex = index;
},
currentIndex: provider.currentindex,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
My First Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
_formKey.currentState.save();
Navigator.push(context, MaterialPageRoute(builder: (context)=>BalancePage()));
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
My Third Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/constant.dart';
class BalancePage extends StatefulWidget {
#override
_BalancePageState createState() => _BalancePageState();
}
class _BalancePageState extends State<BalancePage> {
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Balance'),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Savings',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.green),
),
),
],
),
],
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Budget',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.red),
),
),
],
),
],
),
),
],
),
),
)
],
),
);
}
}
My First Screen Look
My Third Screen Look
Because you're already using Provider I would suggest using a PageController instead of your class Index(), this is because it will do exactly the same but PageController has some other advantages (as controlling a PageView, and it's already there to avoid more boilerplate when changing page)
//Your Savings model
class MySavings{
int savings = 0;
int income = 0;
int expenses = 0;
}
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose(){
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return MultiProvider(
providers: [
ChangeNotifierProvider<PageController>.value(value: _pageController), //now the PageController can be seen as any other Provider
Provider<MySavings>(create: (_) => MySavings())
],
child: Scaffold(
resizeToAvoidBottomInset: false,
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), //So the user doesn't scroll and move only when you pressed the buttons
children: <Widget>[
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
],
),
bottomNavigationBar: MyBottomBar()
)
);
}
}
class MyBottomBar extends StatlessWidget{
#override
Widget build(BuildContext context){
final PageController pageController = Provider.of<PageController>(context, listen: false);
final int index = context.select<PageController, int>((pageController) => pageController.hasClients ? pageController.page.round() : pageController.initialPage);// the index the pageController currently is (if there is no client attached it uses the initialPAge that defaults to index 0)
return BottomNavigationBar(
onTap: (index) {
pageController.jumpToPage(index);
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(index, duration: const Duration(milliseconds: 300), curve: Curves.ease);
},
currentIndex: index,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
Now in SCREEN 1
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
final PageController pageController = Provider.of<PageController>(context, listen: false);
final MySavings mySavings = Provider.of<MySavings>(context, listen: false);
mySavings..income = int.parse(income)..expenses = int.parse(expenses)..savings= int.parse(savings);
_formKey.currentState.save();
pageController.jumpToPage(2); //Index 2 is BalancePage
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(2, duration: const Duration(milliseconds: 300), curve: Curves.ease);
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
And finally in SCREEEN 3 you just call
final MySavings mysavings = Provider.of<MySavings>(context, listen: false);
and use its values (savings, expenses and income) to display in each Text, do some math if you want or change its value (If you want to update as soon as you change them then make MySavings a ChangeNotifier).
If you dont't want to use PageView and stick with the Index class just check the logic and change all the PageController with your index provider and it should work the same
You could save the TextFormField value to a provider property, this way it will be available on all screens

Flutter/Dart: update some variables but not others when using setState()

I'm trying to improve my understanding of Flutter, and am struggling with an issue. I am trying to create an app that presents a list of cards which pull data from a list. There is a button on the bottom that creates a new card when the user clicks it.
I am trying to get each card to display a unique 'Round number'. So for example each time the user clicks the button, a card will be added that displays sequential numbers next to the word 'Round'. Round 1 > Round 2 > Round 3 and so on.
Right now everything works except that every time the button is pressed all the cards are updated with the latest number. And so instead of getting a sequential list of cards, every card is updated to the latest round number.
What am I doing wrong? Thank you.
Here is my code:
import 'package:flutter/material.dart';
class Round {
int roundNumber;
int firstNumber;
int secondNumber;
Round({ this.roundNumber, this.firstNumber, this.secondNumber, });
}
int uid = 1;
List<Round> roundsList = [
Round(roundNumber: uid, firstNumber: 1, secondNumber: 2),
];
class createLevels extends StatefulWidget {
#override
_createLevelsState createState() => _createLevelsState();
}
class _createLevelsState extends State<createLevels> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Create Rounds",)
),
body: Padding(
padding: const EdgeInsets.fromLTRB(20, 20, 20.0, 20),
child: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: roundsList.length,
itemBuilder: (BuildContext context, int whatIsThisVariable) {
return roundCard(Round(roundNumber: uid, firstNumber: 2, secondNumber: 3,));
}
),
),
Text("$roundsList"),
RaisedButton(
onPressed: () {
uid++;
roundsList.add(Round(roundNumber: uid));
setState(() {});
},
child: Text("Add Round"),
),
],
),
),
),
);
}
}
class roundCard extends StatelessWidget {
final Round round;
roundCard(this.round);
// roundsList.add(Round(roundNumber: 1));
#override
Widget build(BuildContext context) {
return Container(
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Spacer(
flex: 1,
),
Expanded(
child: Text('Round ${round.roundNumber}:'),
flex: 12,
),
Expanded(
child: TextFormField(
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: '${round.firstNumber}',
),
),
flex: 3,
),
Spacer(
flex: 1,
),
Expanded(
child: TextFormField(
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: '${round.secondNumber}',
),
),
flex: 3,
),
],
),
)
),
);
}
}
You can copy paste run full code below
You need to pass index not uid
You can adjust first and second number you want
code snippet
itemBuilder: (BuildContext context, int index) {
return roundCard(roundsList[index]);
}),
...
onPressed: () {
uid++;
firstNumber++;
secondNumber++;
roundsList.add(
Round(roundNumber: uid, firstNumber: firstNumber, secondNumber: secondNumber));
setState(() {});
}
working demo
full code
import 'package:flutter/material.dart';
class Round {
int roundNumber;
int firstNumber;
int secondNumber;
Round({
this.roundNumber,
this.firstNumber,
this.secondNumber,
});
}
int uid = 1;
int firstNumber = 2;
int secondNumber = 3;
List<Round> roundsList = [
Round(roundNumber: uid, firstNumber: 1, secondNumber: 2),
];
class createLevels extends StatefulWidget {
#override
_createLevelsState createState() => _createLevelsState();
}
class _createLevelsState extends State<createLevels> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"Create Rounds",
)),
body: Padding(
padding: const EdgeInsets.fromLTRB(20, 20, 20.0, 20),
child: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: roundsList.length,
itemBuilder: (BuildContext context, int index) {
return roundCard(roundsList[index]);
}),
),
Text("$roundsList"),
RaisedButton(
onPressed: () {
uid++;
firstNumber++;
secondNumber++;
roundsList.add(
Round(roundNumber: uid, firstNumber: firstNumber, secondNumber: secondNumber));
setState(() {});
},
child: Text("Add Round"),
),
],
),
),
),
);
}
}
class roundCard extends StatelessWidget {
final Round round;
roundCard(this.round);
// roundsList.add(Round(roundNumber: 1));
#override
Widget build(BuildContext context) {
return Container(
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Spacer(
flex: 1,
),
Expanded(
child: Text('Round ${round.roundNumber}:'),
flex: 12,
),
Expanded(
child: TextFormField(
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: '${round.firstNumber}',
),
),
flex: 3,
),
Spacer(
flex: 1,
),
Expanded(
child: TextFormField(
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: '${round.secondNumber}',
),
),
flex: 3,
),
],
),
)),
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: createLevels(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}