Related
I want to change color of every icon after pressing. But all of icons in a ExpandableContainerchange after pressing one of them.
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
Color _iconColor = Colors.white;
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
.
.
.
),
new ExpandableContainer(
expanded: expandFlag,
expandedHeight: ...
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
decoration:
new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.grey), color: Colors.black),
child: new ListTile(
title: ...
leading: new IconButton(
icon: Icon(Icons.star, color: _iconColor),
onPressed: () {
setState(() {
_iconColor = _iconColor == Colors.white ? Colors.yellow : Colors.white;
});
},
),
subtitle: ...
),
);
},
itemCount: ...,
))
],
),
);
}
}
class ExpandableContainer extends StatelessWidget {
final bool expanded;
final double expandedHeight;
final Widget child;
ExpandableContainer({
#required this.child,
this.expandedHeight,
this.expanded = true,
});
#override
Widget build(BuildContext context) {
.
.
.
}
Whole code:
import 'package:flutter/material.dart';
import 'data.dart';
void main() {
runApp(new MaterialApp(home: new Home()));
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: new Text("Expandable List", style: TextStyle(color: Colors.black)),
backgroundColor: Colors.lightGreen,
),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new ExpandableListView(title: broadcast[index].title, ind: index);
},
itemCount: broadcast.length,
),
);
}
}
class ExpandableListView extends StatefulWidget {
final String title;
final int ind;
const ExpandableListView({this.title, this.ind});
#override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
Color _iconColor = Colors.white;
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
color: Colors.blue[300],
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: new Container(
height: 50.0,
width: 50.0,
decoration: new BoxDecoration(
color: Colors.deepOrange,
shape: BoxShape.circle,
),
child: new Center(
child: new Icon(
expandFlag ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
setState(() {
expandFlag = !expandFlag;
});
}),
new Text(
widget.title,
style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 20.0, color: Colors.black87),
)
],
),
),
new ExpandableContainer(
expanded: expandFlag,
expandedHeight: 90.0 * (broadcast[widget.ind].contents.length < 4 ? broadcast[widget.ind].contents.length : 4), // + (0.0 ?: 29.0),
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
decoration:
new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.grey), color: Colors.black),
child: new ListTile(
title: new Text(
broadcast[widget.ind].contents[index],
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.lightGreen),
textAlign: TextAlign.right,
),
leading: new IconButton(
icon: Icon(Icons.star, color: _iconColor),
onPressed: () {
setState(() {
_iconColor = _iconColor == Colors.white ? Colors.yellow : Colors.white;
});
},
),
subtitle: new Text ('${broadcast[widget.ind].team[index]}\n${broadcast[widget.ind].time[index]} ${broadcast[widget.ind].channel[index]}',
textAlign: TextAlign.right, style:TextStyle(color: Colors.white)),
isThreeLine: true,
),
);
},
itemCount: broadcast[widget.ind].contents.length,
))
],
),
);
}
}
class ExpandableContainer extends StatelessWidget {
final bool expanded;
final double expandedHeight;
final Widget child;
//final Color iconColor;
ExpandableContainer({
#required this.child,
this.expandedHeight,
this.expanded = true,
//this.iconColor,
});
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return new AnimatedContainer(
duration: new Duration(milliseconds: 100),
curve: Curves.easeInOut,
width: screenWidth,
height: expanded ? expandedHeight : 0.0,
child: new Container(
child: child,
decoration: new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.blue)),
),
);
}
}
You need to make the list item a StatefulWidget in which you have the state _iconColor
Stateful List Tile
class StatefulListTile extends StatefulWidget {
const StatefulListTile({this.subtitle, this.title});
final String subtitle, title;
#override
_StatefulListTileState createState() => _StatefulListTileState();
}
class _StatefulListTileState extends State<StatefulListTile> {
Color _iconColor = Colors.white;
#override
Widget build(BuildContext context) {
return new Container(
decoration: new BoxDecoration(
border: new Border.all(width: 1.0, color: Colors.grey),
color: Colors.black),
child: new ListTile(
title: new Text(
widget?.title ?? "",
style: new TextStyle(
fontWeight: FontWeight.bold, color: Colors.lightGreen),
textAlign: TextAlign.right,
),
leading: new IconButton(
icon: Icon(Icons.star, color: _iconColor),
onPressed: () {
setState(() {
_iconColor =
_iconColor == Colors.white ? Colors.yellow : Colors.white;
});
},
),
subtitle: new Text(widget?.subtitle ?? "",
textAlign: TextAlign.right, style: TextStyle(color: Colors.white)),
isThreeLine: true,
),
);
}
}
Usage
class ExpandableListView extends StatefulWidget {
final String title;
final int ind;
const ExpandableListView({this.title, this.ind});
#override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
Color _iconColor = Colors.white;
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
color: Colors.blue[300],
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: new Container(
height: 50.0,
width: 50.0,
decoration: new BoxDecoration(
color: Colors.deepOrange,
shape: BoxShape.circle,
),
child: new Center(
child: new Icon(
expandFlag
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
setState(() {
expandFlag = !expandFlag;
});
}),
new Text(
widget.title,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
color: Colors.black87),
)
],
),
),
new ExpandableContainer(
expanded: expandFlag,
expandedHeight: 90.0 *
(broadcast[widget.ind].contents.length < 4
? broadcast[widget.ind].contents.length
: 4), // + (0.0 ?: 29.0),
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return StatefulListTile(
title: broadcast[widget.ind].contents[index],
subtitle:
'${broadcast[widget.ind].team[index]}\n${broadcast[widget.ind].time[index]} ${broadcast[widget.ind].channel[index]}',
);
},
itemCount: broadcast[widget.ind].contents.length,
))
],
),
);
}
}
You should make the color property distinct for each element in the ListView, what you are doing is that the color is global and shared among all the icons in the ListView, for this reason all icons are changing their color when one icon is pressed.
class Broadcast {
final String title;
List<String> contents;
List<String> team = [];
List<String> time = [];
List<String> channel = [];
Color iconColor = Colors.white; //initialize at the beginning
Broadcast(this.title, this.contents, this.team, this.time, this.channel); //, this.icon);
}
edit your ExpandableListView
class ExpandableListView extends StatefulWidget {
final int ind;
final Broadcast broadcast;
const ExpandableListView({this.broadcast,this.ind});
#override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
edit your Home class
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: new Text("Expandable List", style: TextStyle(color: Colors.black)),
backgroundColor: Colors.lightGreen,
),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new ExpandableListView(title: broadcast[index], ind: index);
},
itemCount: broadcast.length,
),
);
}
}
edit your _ExpandableListViewState
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
#override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
color: Colors.blue[300],
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: new Container(
height: 50.0,
width: 50.0,
decoration: new BoxDecoration(
color: Colors.deepOrange,
shape: BoxShape.circle,
),
child: new Center(
child: new Icon(
expandFlag ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
setState(() {
expandFlag = !expandFlag;
});
}),
new Text(
widget.broadcast.title,
style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 20.0, color: Colors.black87),
)
],
),
),
new ExpandableContainer(
expanded: expandFlag,
expandedHeight: 90.0 * (broadcast[widget.ind].contents.length < 4 ? broadcast[widget.ind].contents.length : 4), // + (0.0 ?: 29.0),
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
decoration:
new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.grey), color: Colors.black),
child: new ListTile(
title: new Text(
broadcast[widget.ind].contents[index],
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.lightGreen),
textAlign: TextAlign.right,
),
leading: new IconButton(
icon: Icon(Icons.star, color: widget.broadcast.iconColor),
onPressed: () {
setState(() {
widget.broadcast.iconColor = widget.broadcast.iconColor == Colors.white ? Colors.yellow : Colors.white;
});
},
),
subtitle: new Text ('${broadcast[widget.ind].team[index]}\n${broadcast[widget.ind].time[index]} ${broadcast[widget.ind].channel[index]}',
textAlign: TextAlign.right, style:TextStyle(color: Colors.white)),
isThreeLine: true,
),
);
},
itemCount: broadcast[widget.ind].contents.length,
))
],
),
);
}
}
I'm having trouble passing the data that's been filled in a textformfields and selected in a dropdown menu.
I'm trying to use the Map function to pass down String values so that I can also pass down all types of values in the future (ex. int, bool, double etc.), however it's not working so I need someone to check it out.
main.dart
import 'package:flutter/material.dart';
import 'package:workoutapp/auth/auth.dart';
import 'package:workoutapp/auth/root_page.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
void main(List<String> args) {
runApp(
WorkoutManager(),
);
}
class WorkoutManager extends StatelessWidget {
#override
Widget build(BuildContext context) {
return AuthProvider(
auth: Auth(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Workout Manager',
home: RootPage(),
theme: ThemeData(
primaryColor: Colors.indigo,
primarySwatch: Colors.indigo,
accentColor: Colors.indigoAccent,
hintColor: Colors.indigo,
brightness: Brightness.dark,
),
),
);
}
}
HomePage
import 'package:flutter/material.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
import './profile_account_page.dart';
import './routines_create_page.dart';
import '../objects/Routines/routines_manager.dart';
import '../tools/custom_drawer.dart';
class HomePage extends StatelessWidget {
final VoidCallback onSignedOut;
final List<Map<String, String>> routines;
HomePage({Key key, this.onSignedOut, this.routines}) : super(key: key);
void _signedOut(BuildContext context) async {
try {
var auth = AuthProvider.of(context).auth;
await auth.signOut();
onSignedOut();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Workout Manager', style: TextStyle(color: Colors.white)),
centerTitle: false,
actions: <Widget>[
FlatButton(
child: Text('Logout'),
onPressed: () {
return _signedOut(context);
},
),
IconButton(
icon: Icon(Icons.account_box),
tooltip: 'Profile Account',
color: Colors.white,
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return ProfileAccountPage();
}));
},
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesPageCreate();
}));
},
),
body: RoutinesManager(),
drawer: CustomDrawer(),
);
}
}
RoutineManager
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines.dart';
class RoutinesManager extends StatefulWidget {
final Map<String, String> startingRoutine;
RoutinesManager({this.startingRoutine});
#override
_RoutinesManagerState createState() => _RoutinesManagerState();
}
class _RoutinesManagerState extends State<RoutinesManager> {
List<Map<String, String>> _routines = [];
#override
void initState() {
if (widget.startingRoutine != null) {
_routines.add(widget.startingRoutine);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: Routines(_routines),
)
],
);
}
}
RoutinesCreatePage
import 'package:flutter/material.dart';
import 'package:workoutapp/pages/home_page.dart';
class RoutinesPageCreate extends StatefulWidget {
#override
_RoutinesPageCreateState createState() => _RoutinesPageCreateState();
}
class _RoutinesPageCreateState extends State<RoutinesPageCreate> {
final formKey = GlobalKey<FormState>();
List<Map<String, String>> _routines = [];
String _routineName, _routineDescription;
var _routineNameController = TextEditingController();
var _routineDescriptionController = TextEditingController();
List<DropdownMenuItem<String>> _dropdownListBodyPartMenuItem = [];
List<String> _dropdownListBodyPart = [
'Chest',
'Back',
'Leg',
'Shoulder',
'Abs',
];
String _selectedBodyPart;
List<DropdownMenuItem<String>> _dropdownListDayOfWeekMenuItem = [];
List<String> _dropdownListDayOfWeek = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
String _selectedDayOfWeek;
void loadBodyPartData() {
_dropdownListBodyPartMenuItem = [];
_dropdownListBodyPartMenuItem = _dropdownListBodyPart.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
void loadDayOfWeekData() {
_dropdownListDayOfWeekMenuItem = [];
_dropdownListDayOfWeekMenuItem = _dropdownListDayOfWeek.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
final _scaffoldState = GlobalKey<ScaffoldState>();
void _showSnakBarReset() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Showing SnackBar TEST'),
),
);
}
void _showSnakBarCreateWorkoutRoutine() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Workout Routine has been created'),
),
);
}
void _addRoutine(Map<String, String> routine) {
setState(() {
_routines.add(routine);
});
}
#override
Widget build(BuildContext context) {
loadBodyPartData();
loadDayOfWeekData();
return Scaffold(
key: _scaffoldState,
appBar: AppBar(
title: Text('Create Routines'),
),
body: Container(
padding: EdgeInsets.all(15.0),
child: Form(
key: formKey,
child: ListView(children: buildInputs() + buildCreateButtons()),
),
),
);
}
List<Widget> buildInputs() {
TextStyle textStyle = Theme.of(context).textTheme.title;
return [
TextFormField(
controller: _routineNameController,
validator: (value) {
if (value.length > 20) {
return 'Not a valid Routine Name';
}
},
onSaved: (value) {
return _routineName = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Routine Name',
hintText: 'Enter the Routine Name for this day',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: EdgeInsets.all(7.0)),
TextFormField(
controller: _routineDescriptionController,
validator: (value) {
if (value.length > 50) {
return 'Invalid: The Description must be 50 characters or less.';
}
},
onSaved: (value) {
return _routineDescription = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Description',
hintText: 'Enter the description of the Routine.',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: const EdgeInsets.all(7.0)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedBodyPart,
items: _dropdownListBodyPartMenuItem,
hint: Text('Select Body Part', style: textStyle),
onChanged: (value) {
setState(() {
_selectedBodyPart = value;
});
})),
Padding(
padding: const EdgeInsets.all(1.0),
),
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedDayOfWeek,
items: _dropdownListDayOfWeekMenuItem,
hint: Text('Select Day of Week', style: textStyle),
onChanged: (value) {
setState(() {
_selectedDayOfWeek = value;
});
},
),
),
Padding(
padding: const EdgeInsets.all(4.0),
)
],
),
];
}
List<Widget> buildCreateButtons() {
return [
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorDark,
color: Theme.of(context).accentColor,
child: Text('Create Workout Routine'),
onPressed: () {
if (formKey.currentState.validate()) {
_showSnakBarCreateWorkoutRoutine();
formKey.currentState.save();
_addRoutine({
'routineName': 'Chest Workout',
'description': 'Heavy',
'bodyPart': 'Chest',
'week': 'Monday',
});
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return HomePage();
}));
} else {
return null;
}
}),
),
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorLight,
color: Theme.of(context).primaryColorDark,
child: Text('Reset'),
onPressed: () {
setState(() {
_showSnakBarReset();
formKey.currentState.reset();
_selectedBodyPart = null;
_selectedDayOfWeek = null;
});
},
),
),
],
),
),
];
}
}
Routines
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines_detail.dart';
class Routines extends StatelessWidget {
final List<Map<String, String>> routines;
Routines(this.routines);
Widget _buildRoutinesItem(BuildContext context, int index) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Expanded(
child: Card(
margin: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['routineName'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['description'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['bodyPart'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['week'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Text('Details'),
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesDetail(
routines[index]['routineName'],
routines[index]['description'],
routines[index]['bodyPart'],
routines[index]['week']);
}));
},
)
],
),
)
],
),
),
);
}
Widget _buildRoutinesList(context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
Widget routinesCards = Container(
child: Container(
child: Center(
child: Text("No routines found, please add some.", style: textStyle),
),
),
);
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}
return routinesCards;
}
#override
Widget build(BuildContext context) {
return _buildRoutinesList(context);
}
}
RoutineDetailPage
import 'package:flutter/material.dart';
class RoutinesDetail extends StatelessWidget {
final String routineName, description, bodyPart, week;
RoutinesDetail(this.routineName, this.description, this.bodyPart, this.week);
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text(routineName),
centerTitle: true,
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routineName, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(description, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(bodyPart, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(week, style: textStyle)),
Container(
padding: EdgeInsets.all(5.0),
child: RaisedButton(
child: Text('Delete'),
onPressed: () {
Navigator.pop(context);
},
),
),
],
),
),
);
}
}
As you can see, I'm trying to separate the code into multiple files as much as possible, so it's more "readable" and make it easy for myself to make changes to the code whenever I have to in the future.
The problem is, it's quite spit up, I don't understand how to use the data and pass it down or up to the pages or widgets as there are multiple stateful and stateless widgets that are suppose to work together to make this app possible.
You'll notice on the HomePage file (StatelessWidget), I'm trying to show the Scaffold body argument with the RoutinesManager StatefulWidget, which is in a different file. At the same time in the HomePage file, I have a Scaffold floatingActionButton argument that will take you to the RoutinesCreatePage StatefulWidget to create a List of Cards (StatelessWidget) using the ListView.builder(). However, no Card gets created under the HomePage after the "Create Workout Routine" RaisedButton gets pressed in the RoutinesCreatePage and no data gets passed.
Can someone please help me out here as I am totally clueless. Also, I'm fairly a beginner regarding flutter/dart so a solution with a relatively easy to understand explanation would be very helpful.
Note: I do have other files that contribute to this app, however I don't think they're part of the problem so I left them out intentionally.
If more information is needed, please do let me know.
Thanks you!
it looks like you misunderstand what state in Flutter is. To explain in short, state is the internal status/data/... that belongs that that specific widget. StatefulWidget has state to determine if UI should be re-rendered on its own state change. External widgets never know about other widgets' states.
So it means, any state change happening inside RoutinesCreatePage widget, only that RoutinesCreatePage knows and reacts. Unless, you inform other widgets to know something has changed.
Alright, so talking about navigation, it works like a stack structure. HomePage trigger a push to RoutinesCreatePage, then to return, you need to pop, not another push.
Here a quick fix for your code, you can try.
HomePage
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
handleNewRoutine(); <--- this is to handle navigation and retrieve returning data from pop
},
),
Future handleNewRoutine() async {
var newRoutine = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => RoutinesPageCreate());
)
if (newRoutine == null) {
// nothing returns from RoutinesPageCreate widget
// so do nothing then
} else {
// add to routine list
// and trigger list re-rendering
setState(() {
this.routines.add(newRoutine);
});
}
}
RoutinesCreatePage: when clicking submit button, just populate all data from input fields, make object model and pop to return data to where this widget was pushed.
onPressed: () {
var newRoutine = .... // populate from UI to create new Routine model object.
Navigator.pop(context, newRoutine);
}
Also, take time to read the navigation guide from official Flutter documentation. It is very detailed on this part. https://flutter.io/docs/cookbook/navigation/returning-data
Some additional comments to your code:
in RoutinesCreatePage you don't need to know application level state, I mean _routines variable is unnecessary. You only need one object to store new routine to pop back to HomePage.
in Routines, this method Widget _buildRoutinesList(context) having unused ListView creation.
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}
I'm trying to create a List of data from online server Firebase using StreamBuilder bu the checkbox won't get checked.
I have used StreamBuilder to get the data and used LisTile widget to build the list items but the checkboxtilelist widget won't work after defining setState() function. And buildBody is defined under build Widget class.
Widget buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('hisab').snapshots(),
builder: (context, snapshots) {
if (!snapshots.hasData) {
return LinearProgressIndicator();
}
return _buildList(context, snapshots.data.documents);
}
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: EdgeInsets.only(top: 20.0),
children: snapshot.map((data) => _buildListitem(context, data)).toList(),
);
}
Widget _buildListitem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot((data));
bool _values = false;
void _onChanged(bool newValue) {
setState(() {
_values = newValue;
});
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 9.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(5.0),
),
child: new ListTile(
onTap: () {
_onChanged(!_values);
},
leading: CircleAvatar(child: Text(record.name[0])),
title: new Column(
children: <Widget>[
new CheckboxListTile(
title: Text(record.name),
value: _values,
onChanged: _onChanged,
)
],
),
),
),
);
}
It's good idea if you create new stateful widget class:
class CustomListItemWidget extends StatefulWidget {
CustomListItemWidget({Key key, #required this.record}) : super(key: key);
final record;
#override
State createState() => _CustomListItemWidgetState();
}
class _CustomListItemWidgetState extends State<CustomListItemWidget> {
bool _values = false;
void _onChanged(bool newValue) {
setState(() {
_values = newValue;
});
}
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 9.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(5.0),
),
child: new ListTile(
onTap: () {
_onChanged(!_values);
},
leading: CircleAvatar(child: Text(widget.record.name[0])),
title: new Column(
children: <Widget>[
new CheckboxListTile(
title: Text(widget.record.name[0]),
value: _values,
onChanged: _onChanged,
)
],
),
),
),
);
}
}
Next, you can pass value from your method _buildListitem:
Widget _buildListitem(BuildContext context, DocumentSnapshot data) {
return CustomListItemWidget(
record: Record.fromSnapshot((data)),
);
}
File:homepage.dart
class _HomePageState extends State<HomePage> {
var _scaffoldBody;
var _scaffoldTitle;
#override
initState() {
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new Center(child:CircularProgressIndicator());
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: new Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color:Theme.of(context).accentColor,
),
),
ListTile(
title: Text('Home'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("Home");
_scaffoldBody=new Text("Home Page");
});
Navigator.pop(context);
},
),
ListTile(
title: Text('MenuItem1'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("1st Menu");
_scaffoldBody=new TestPage("Page 1");
});
Navigator.pop(context);
},
),
ListTile(
title: Text('MenuItem2'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("2nd Item");
_scaffoldBody=new TestPage("Page 2");
});
Navigator.pop(context);
},
),
],
),
),
appBar: new AppBar(
title: _scaffoldTitle,
elevation: 2.0,
actions: <Widget>[
],
),
body:_scaffoldBody,
);
}
file: TestPage.dart
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget{
final String rollNumber;
TestPage(this.rollNumber);
#override
TestPageState createState() => new TestPageState(rollNumber);
}
class TestPageState extends State<TestPage>{
String rollNumber;
TestPageState(this.rollNumber);
#override
Widget build(BuildContext context) {
return new Text(rollNumber);
}
}
Output:
When I chose : "Home" from drawer it shows "Home Page"
Then I chose : "MenuItem1" it showed "Page 1"
Then I chose : "MenuItem2" it showed same "Page 1" (unexpected)
Then I chose : "Home" it showed "Home Page"
Then I chose : "MenuItem2" it showed correctly as "Page 2"
Then I chose : "MenuItem1" it showed "Page 2" (unexpected)
unable to solve this.Stuck!! Any solutions are appreciated. Thanks in advance!!
Update your TestPart.dart as follow:
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget{
final String rollNumber;
TestPage(this.rollNumber);
#override
TestPageState createState() => new TestPageState();
}
class TestPageState extends State<TestPage>{
#override
Widget build(BuildContext context) {
return new Text(widget.rollNumber);
}
}
My StudentPage Class
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'calendar_utils.dart';
import 'dart:async';
final mainReference = FirebaseDatabase.instance.reference();
class StudentPage extends StatefulWidget{
final String rollNumber;
StudentPage(this.rollNumber);
#override
StudentPageState createState() => new StudentPageState(rollNumber);
}
class StudentPageState extends State<StudentPage>{
final String currentRoll,currentYear="2018-19";
StudentPageState(this.currentRoll);
List<String> academicMonth=["June","July","August","September","October","November","December",
"January","February","March","April","May"];
int firstHalfYear=2018,secondHalfYear=2019;
List<Widget> _monthListArray=[new ListTile(title:new Text("Academic Year",style: new TextStyle(fontWeight: FontWeight.bold,fontSize: 20.0),),)];
List<Widget> _listView;
int _no_of_working=0;
int _no_of_present=0;
#override
void initState() {
// TODO: implement initState
_listView=[new Center(
child: new CircularProgressIndicator(),
)];
_loadMonths();
}
#override
Widget build(BuildContext context) {
return new RefreshIndicator(child: new ListView(
children: _listView,
), onRefresh: _loadMonths);
}
Future<Null> _loadMonths() async {
_listView.clear();
await mainReference.child("XXXX").child("attendance").child(
widget.rollNumber).child(currentYear).once().then((
DataSnapshot dataSnapshot) {
try {
int monthIndex=5; //monthIndex starts from June
for(var month in academicMonth){
debugPrint("Month:"+month);
monthIndex=(monthIndex+1)%12; //month index cycles throughout 1-12
if(monthIndex==0) monthIndex=12;
List<Widget> _daysList=[];
_monthListArray.add(new Padding(padding: EdgeInsets.all(16.0),child: new Text(month+" "+(monthIndex<6?secondHalfYear:firstHalfYear).toString(),style: new TextStyle(color: Colors.black87,fontWeight: FontWeight.bold,fontSize: 20.0),),)); //initializing the month
_monthListArray.add(new Padding(padding: EdgeInsets.only(top: 10.0,bottom: 10.0),child:
new Row(children: <Widget>[
new Expanded(
child: new Center(child: new Text("S",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("M",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("T",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("W",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("T",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("F",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
new Expanded(
child: new Center(child: new Text("S",style: new TextStyle(fontWeight: FontWeight.bold),),),
),
],),));
debugPrint(monthIndex.toString());
int freeSpace=CalendarUtils(1,monthIndex,monthIndex<6?secondHalfYear:firstHalfYear).getDayFromDate();
debugPrint("FreeSpace---"+freeSpace.toString());
if(freeSpace!=0){
for (var i = 0; i < freeSpace; i++) {
_daysList.add(new Text(""));
}
}
debugPrint(monthIndex.toString());
var year=monthIndex<6?secondHalfYear:firstHalfYear;
debugPrint("Year"+year.toString());
debugPrint("Forloop limit:"+CalendarUtils(1,monthIndex,monthIndex<6?firstHalfYear:secondHalfYear).numberOfDays().toString());
for(var day=1;day<=CalendarUtils(1,monthIndex,monthIndex<6?secondHalfYear:firstHalfYear).numberOfDays();day++){
try {
//debugPrint(day.toString()+":"+dataSnapshot.value[month][day].toString());
if (CalendarUtils(day, monthIndex,
monthIndex < 6 ? secondHalfYear: firstHalfYear)
.getDayFromDate() != 0){
if (dataSnapshot.value[month][day].toString() == "1") {
_no_of_working++;
_no_of_present++;
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
color: Colors.green),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.white),
),
),
)
);
}
else if (dataSnapshot.value[month][day].toString() == "0"){
_no_of_working++;
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
color: Colors.redAccent),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.white),
),
),
)
);
}
else {
_daysList.add(
new Padding(padding: EdgeInsets.only(left: 10.0,right: 10.0,top: 2.0,bottom: 2.0),
child: new Container(
alignment: Alignment.center,
width: 30.0,
height: 30.0,
decoration: new BoxDecoration(
borderRadius: new BorderRadius.all(new Radius.circular(50.0)),
),
child: new Text(
day.toString(),
style: new TextStyle(color: Colors.black),
),
),
)
);
}
}else {
_daysList.add(
new Center(child: new Text(day.toString(), style:
new TextStyle(color: Colors.black45),)));
}
}catch (e){
_daysList.add(new Center(child:new Text(day.toString(),style:
new TextStyle(color: Colors.black),) ));
}
}
Widget _daysGrid=new GridView.count(crossAxisCount: 7,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
childAspectRatio: 1.5,
children: _daysList,
);
_monthListArray.add(_daysGrid);
}
}catch(e){}
_monthListArray.add(new Text((_no_of_present/_no_of_working).toString()));
});
this.setState((){
_listView=_monthListArray;
});
}
}
My HomePage.dart
import 'package:flutter/material.dart';
import 'package:smart_school_parent/TestPage.dart';
import 'package:smart_school_parent/attendance.dart';
import 'package:smart_school_parent/post.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:smart_school_parent/auth.dart';
import 'dart:async';
class HomePage extends StatefulWidget {
final BaseAuth auth;
final VoidCallback onSignOut;
HomePage({Key key, this.auth, this.onSignOut}) : super(key: key);
#override
_HomePageState createState() => new _HomePageState(this.auth);
}
class _HomePageState extends State<HomePage> {
final mainReference = FirebaseDatabase.instance.reference();
List<PostData> post_list = new List();
var _scaffoldBody;
var _loading;
var _currentYear;
var _scaffoldTitle;
List<Widget> _childrenList=[new Text("Profiles",textAlign: TextAlign.left,style: new TextStyle(fontWeight: FontWeight.bold),)];
BaseAuth auth;
_HomePageState(this.auth);
#override
initState() {
//_children=updateChildren();
_updateChildren();
getList();
_loading=true ;
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new Center(child:CircularProgressIndicator());
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: new Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('XXXXx'),
decoration: BoxDecoration(
color:Theme.of(context).accentColor,
),
),
ListTile(
title: Text('Wall'),
onTap: () {
setState(() {
_scaffoldTitle=new Text("Wall");
_scaffoldBody=new RefreshIndicator(child: _loadWall(), onRefresh: getList);
});
Navigator.pop(context);
},
),
Column(
children: _childrenList,
),
],
),
),
appBar: new AppBar(
title: _scaffoldTitle,
elevation: 2.0,
actions: <Widget>[
],
),
body:_scaffoldBody,
);
}
Future <Null> getList() async {
await mainReference.child("NISE-Coimbatore").child("posts").once().then((DataSnapshot dataSnapshot) {
this.setState(() {
post_list.clear();
if(dataSnapshot.value!=null){
for (var value in dataSnapshot.value.values) {
post_list.add(new PostData.fromJson(value));
//debugPrint(value.toString());
}
}else{
this.setState((){
});
}
});
});
setState(() {
_scaffoldBody=new RefreshIndicator(child: _loadWall(), onRefresh: getList);
});
}
Widget _loadWall(){
return Stack(
children: <Widget>[
new ListView.builder(itemBuilder: (BuildContext context,int index){
return new Post(post_list[index].image,post_list[index].title,post_list[index].content);
},
itemCount: post_list == null ? 0 : post_list.length,)
],
);
}
_updateChildren() async {
_currentYear= await mainReference.child("attendance").child("currentYear").once();
await auth.currentUser().then((String userId) async{
mainReference.child("NISE-Coimbatore").child("parents").child(userId).child('children').once().then((DataSnapshot dataSnapshot){
for (var value in dataSnapshot.value){
this.setState((){
_childrenList.add(
new Padding(
padding: EdgeInsets.only(left: 25.0),
child: ListTile(
title: Text(value.toString()),
onTap: () {
super.setState(() {
_scaffoldTitle=new Text(value.toString());
this._scaffoldBody=new StudentPage(value.toString());
});
Navigator.pop(context);
},
),
),
);
});
//debugPrint("Childrrncount::"+value.toString());
}
});
});
}
}
class PostData{
String title;
String content;
String image;
PostData(this.title, this.content, this.image);
PostData.fromJson(var value) {
this.title = value['title'];
this.content = value['content'];
this.image = value['image'];
}
}
_childrenList has two elements. The datasnapshot.values has [15505,15501] two roll numbers
Both rollnumbers from firebase appear on the drawer box and on tap it is expected to show StudentPage(15501.tostring()) or StudentPage(15505.tostring())
it works as expected if select "Wall" from drawer and then any of the "rollNumbers"
it is not working if i switch from one of the rollNumbers to other rollNumber in the drawer.
Similar to my first post. Only the _scaffoldTitle changes accordingly.
I've the below code for entering some data, I do not know how to handle it!
i.e. What shall I write at the onPressed for the IconButton so that the data is read from all the elements (name, birthday, ...)? and how to display it in Dialog to check if read correctly?
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.deepOrange,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _value=false;
double _bodyHeight=0.0;
void onchange(bool value) {
setState(() {
_value = value;
this._bodyHeight = (value == true) ? 400.0 : 0.0;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey[500],
appBar: new AppBar(
title: new Text(widget.title),
),
body: new SingleChildScrollView(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Card(
child: new Container(
height: 50.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Text("Select me pls"),
new Switch(value: _value, onChanged: (bool value) => onchange(value)),
],
),
),
),
new Card(
child: new AnimatedContainer(
child: new ListView(
children: <Widget>[
new ListTile(
leading: const Icon(Icons.person),
title: new TextField(
decoration: new InputDecoration(
hintText: "Name",
),
),
),
new ListTile(
leading: const Icon(Icons.phone),
title: new TextField(
decoration: new InputDecoration(
hintText: "Phone",
),
),
),
new ListTile(
leading: const Icon(Icons.email),
title: new TextField(
decoration: new InputDecoration(
hintText: "Email",
),
),
),
const Divider(
height: 1.0,
),
new ListTile(
leading: const Icon(Icons.label),
title: const Text('Nick'),
subtitle: const Text('None'),
),
new ListTile(
leading: const Icon(Icons.today),
title: const Text('Birthday'),
subtitle: const Text('February 20, 1980'),
),
new IconButton(icon: const Icon(Icons.save),
onPressed: null
/*
*
* What shall I write here to read the data in the elements
*
*
*
* */
),
],
),
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 500),
height: _bodyHeight,
// color: Colors.red,
),
),
],
),
),
);
}
}
One way is that TextFields take a property called TextEditingController which allow you to access the value of the TextField.
And to show a dialog you can just call showDialog() function.
class TextFieldExample extends StatefulWidget {
#override
_TextFieldExampleState createState() => new _TextFieldExampleState();
}
class _TextFieldExampleState extends State<TextFieldExample> {
TextEditingController c1;
TextEditingController c2;
#override
void initState() {
c1 = new TextEditingController();
c2 = new TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new TextField (
controller: c1,
),
new TextField(
controller: c2,
),
new OutlineButton(onPressed: () {
showDialog(child: new AlertDialog(
content: new Text("You entered ${c1.text} ${c2.text} ")
),
context: context
);
},
child: new Text("Show Dialog"),
)
],
),
),
);
}
}