Flutter: how to show number of items in List - flutter

While learning Flutter, I have written a CRUD program that shows a list of items. I want to show at the bottom of the screen the number of items in the list, but I have been unable to achieve that. Currently the code shown contains (at the end) a BottomNavigationBar and a BottomNavigationBarItem where I attempt to show the number of items in the list, viz:
title: Text("Items = $this.itemCount")), // title: Text("")),
However it just shows "..." for the number of items. I would appreciate someone showing me how to achieve what I require.
class NotesList extends StatefulWidget {
#override
NotesListPageState createState() => NotesListPageState();
}
class NotesListPageState extends State<NotesList> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Notes List'),
centerTitle: true,
),
body: new Container(
padding: new EdgeInsets.all(16.0),
child: new FutureBuilder<List<Map>>(
future: fetchDataFromDb(),
builder: (context, snapshot) {
if (snapshot == null) {
return Container(
alignment: AlignmentDirectional.center,
child: CircularProgressIndicator(),
);
} else if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot == null ? 0 : snapshot.data.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
leading: (IconButton /* Edit */ (
color: Colors.blue,
icon: new Icon(Icons.edit),
onPressed: () => _showEditScreen(
Crud.eUpdate, snapshot.data[index]))),
onLongPress: () => _showEditScreen(
Crud.eRead, snapshot.data[index]),
trailing: (IconButton(
color: Colors.red,
icon: new Icon(Icons.delete),
onPressed: () => _showEditScreen(
Crud.eDelete, snapshot.data[index])))),
]);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
} else {
return new Text("No data in table");
}
},
),
),
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) {
if (index == 1) {
Navigator.of(context).pop();
}
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.info),
title: Text("Items = $this.itemCount")), // title: Text("")),
BottomNavigationBarItem(
icon: Icon(Icons.add),
title: Text('Create'),
),
],
));
}
'''

In your state class add at top
int count = 0;
add the code
WidgetsBinding.instance
.addPostFrameCallback((_) {
setState(){
count = snapshot.data.length;
}
});
between these two lines
else if (snapshot.hasData) {
return ListView.builder(
and change the title property to
title: Text("Items = $count")),

Show your text like this -
title: Text("Items = ${this.itemCount}")),
or like -
title: Text("Items = " + this.itemCount)),

Related

how get selected index of multiple ExpansionTile in flutter

how get selected index of multiple ExpansionTile in flutter ?
i need sidebar menu with multiple expansiontile and listtile.
how can i get selected index to change selected color menu with provider or bloc ?
children: [
ExpansionTile(
title: Text('main a'),
children: [
ListTile(
title: Text('a1'),
),
ListTile(
title: Text('a2'),
),
ExpansionTile(
title: Text('a3'),
children: [
ListTile(
title: Text('a31'),
),
ListTile(
title: Text('a32'),
),
ListTile(
title: Text('a32'),
),
],
),
],
),
ExpansionTile(
title: Text('main b'),
children: [
ListTile(
title: Text('b1'),
),
ListTile(
title: Text('b2'),
),
ListTile(
title: Text('b3'),
),
],
),
],
You can use onTap from ListTile, and create state variables to hold selected item. Like here I am using String. Based on your data, creating model class or map might be better choice.
String? aValue;
....
ExpansionTile(
title: Text('main a'),
children: [
ListTile(
title: Text('a1'),
onTap: () {
aValue = "a1";
setState(() {});
},
),
You can use a ListView to contain the ExpansionTile widgets and a ListTile widgets. Then you can use a currentIndex variable to keep track of the index of the currently selected menu item. You can use a Provider or BLoC to manage the currentIndex variable and to notify the widget tree when the value of currentIndex changes.
Here is the full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MenuModel(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ExpansionTile Demo'),
),
body: MenuList(),
);
}
}
class MenuList extends StatelessWidget {
#override
Widget build(BuildContext context) {
final model = Provider.of<MenuModel>(context);
return ListView(
children: <Widget>[
ExpansionTile(
title: Text('Menu 1'),
children: <Widget>[
ListTile(
title: Text('Menu 1.1'),
onTap: () {
model.updateIndex(0);
},
selected: model.currentIndex == 0,
),
ListTile(
title: Text('Menu 1.2'),
onTap: () {
model.updateIndex(1);
},
selected: model.currentIndex == 1,
),
],
),
ExpansionTile(
title: Text('Menu 2'),
children: <Widget>[
ListTile(
title: Text('Menu 2.1'),
onTap: () {
model.updateIndex(2);
},
selected: model.currentIndex == 2,
),
ListTile(
title: Text('Menu 2.2'),
onTap: () {
model.updateIndex(3);
},
selected: model.currentIndex == 3,
),
],
),
],
);
}
}
class MenuModel with ChangeNotifier {
int _currentIndex = 0;
int get currentIndex => _currentIndex;
void updateIndex(int index) {
_currentIndex = index;
notifyListeners();
}
}
This is a hassle to dynamically change the color of the ListTile() which have two different parent widget but with some extra code, you can do the same.
Full Code
// You can also use `Map` but for the sake of simplicity I'm using two separate `List`.
final List<String> _parentlist1 = ["a1", "a2"];
final List<String> _childOfParentlist1 = ["a31", "a32", "a34"];
final List<bool> _isSelectedForParentList1 = List.generate(
2,
(i) =>
false); // Fill it with false initially and this list for all the textList
final List<bool> _isSelectedForChildOfParentList1 =
List.generate(2, (i) => false);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ExpansionTile(
title: const Text('main a'),
children: [
ListView.builder(
itemBuilder: (_, i) {
return ListTile(
tileColor: _isSelectedForParentList1[i]
? Colors.blue
: null, // If current item is selected show blue color
title: Text(_parentlist1[i]),
onTap: () => setState(() => _isSelectedForParentList1[i] =
!_isSelectedForParentList1[i]), // Reverse bool value
);
},
),
ExpansionTile(
title: const Text('a3'),
children: [
ListView.builder(
itemBuilder: (_, i) {
return ListTile(
tileColor: _isSelectedForChildOfParentList1[i]
? Colors.blue
: null, // If current item is selected show blue color
title: Text(_childOfParentlist1[i]),
onTap: () => setState(() =>
_isSelectedForChildOfParentList1[i] =
!_isSelectedForChildOfParentList1[
i]), // Reverse bool value
);
},
),
],
),
],
),
);
}

I cannot send data to home screen using Flutter/Dart

I did a todo list, I want to send data home screen but I cannot.
I want to get data from page 2 with to do list app and create object on page 1 and add it to the list, but I can't send it with constructor.
class IlkEkran extends StatefulWidget {
String? works;
toDolist("Limon ", DateTime.now())
];
toDolist selectedIndex = toDolist.testerobject();
String? works;
_IlkEkranState({String? works}) { error is here
this.works = works;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(children: [
Flexible(
child: ListView.builder(
itemCount: listem.length,
itemBuilder: (context, index) {
return Card(
margin: EdgeInsets.all(5),
elevation: 20,
child: ListTile(
title: Text(listem[index].yapilacaklar),
subtitle: Text(listem[index].tarih.toString()),
leading: CircleAvatar(child: Icon(Icons.shopping_basket)),
trailing: Wrap(
spacing: 5,
children: [
IconButton(
onPressed: () {
selectedIndex = listem[index];
setState(() {
listem.remove(selectedIndex);
});
},
icon: Icon(Icons.delete)),
IconButton(
onPressed: () {
setState(() {
toDolist newWork =
toDolist(works!, DateTime.now());
listem.add(newWork);
});
},
icon: Icon(Icons.notification_important)),
],
),
),
);
}),
),
]),
);
}
}

How to add icon/image along with popup menu in flutter?

Below is my code.
var choices = ['Settings', 'Log Out'];
void choiceAction(String choice){
print(choice);
}
Widget aapBarSection(String title, Color color, BuildContext context){
return AppBar(
title: Text(title, style:TextStyle(fontFamily: 'Poppins-Regular'), ),
centerTitle: true,
backgroundColor: color,
actions: [
PopupMenuButton<String>(
onSelected: choiceAction,
itemBuilder: (BuildContext context){
return choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
)
],
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
exit(0);
},
),
);
}
menu items are showing but how to show image/icon as per the items like for settings(settings icon) and for logout(logout icon) with it?
Can anybody help me please!
You can use ListTile as child or Row.
PopupMenuItem<String>(
value: choice,
child: ListTile(
leading: Icon(Icons.work), // your icon
title: Text(choice),
),
)
var choices = [
{'title': 'Home', 'icon': const Icon(Icons.home)},
{'title': 'Profile', 'icon': const Icon(Icons.people)},
{'title': 'Logout', 'icon': const Icon(Icons.logout)}
];
var actions = [
PopupMenuButton<String>(
onSelected: choiceAction,
itemBuilder: (BuildContext ctx) {
return choices.map((ch) {
return PopupMenuItem<String>(
value: ch['title'].toString(),
child: ListTile(
leading: ch['icon'] as Widget,
title: Text(ch['title'].toString())));
}).toList();
})
];
void choiceAction(String choice){
print(choice);
}
class _HomeVendorPageState extends State<HomeVendorPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: actions,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [])));
}
}

Build function returned null

I have an app which generates a new Card wrapped in a GestureDetector when the FAB of Scaffold is pressed. the app was working fine but i wanted to implement a delete card functionality and when i added that, the app doesnt recognize the return statements in the build function. I feel like im missing something obvious but since i am new to flutter i am struggling to find what went wrong.
Whole code:
class _Starting_screenState extends State<Starting_screen> {
int _count = 1;
#override
Widget build(BuildContext context) {
{
List<Widget> cardList = new List.generate(
_count, (int i) => new createCard());
SystemChrome.setEnabledSystemUIOverlays([]);
_deleteNoDo(int id, int index) async {
debugPrint("Deleted Item!");
setState(() {
cardList.removeAt(index);
});
void addItems() async {
setState(() {
cardList.insert(0, new GestureDetector(
onTap: () async {
await Navigator.push(context, MaterialPageRoute(
builder: (context) =>
TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child: ListTile(
title: Text("project 1"),
trailing: new Listener(
key: new Key(UniqueKey().toString()),
child: new Icon(Icons.remove_circle,
color: Colors.redAccent,),
onPointerDown: (pointerEvent) => _deleteNoDo(id, index),
),
subtitle: whitefontstylemont(text: "project 1",
size: 20,)) //this is just a custom TextStyle
),
));
});
}
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
setState(() {
_count += 1;
});
},
heroTag: "btn2",
child: Icon(Icons.add, color: Color(whitecolor),),
backgroundColor: Color(redcolor),),
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
flexibleSpace: FlexibleSpaceBar(
),
actions: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 20, right: 10),
child: whitefontstyle(
text: "Remaining tasks for today - ${cardList
.length}", size: 20,),
),
),
],
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context,
index) {
return cardList[index];
},
childCount: cardList.length
)
),
]
)
);
}
}
}
}
delete function:
_deleteNoDo(int id, int index) async {
debugPrint("Deleted Item!");
setState(() {
cardList.removeAt(index);
});
function which adds a card :
void addItems() async {
setState(() {
cardList.insert(0, new GestureDetector(
onTap: () async {
await Navigator.push(context, MaterialPageRoute(
builder: (context) =>
TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child: ListTile(
title: Text("project 1"),
trailing: new Listener(
key: new Key(UniqueKey().toString()),
child: new Icon(Icons.remove_circle,
color: Colors.redAccent,),
onPointerDown: (pointerEvent) => _deleteNoDo(id, index),
),
subtitle: whitefontstylemont(text: "project 1", size: 20,)) //this is just a custom TextStyle
),
));
});
}
code where cards are displayed in a list
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context, index) {
return cardList[index]; // this is where the cards are displayed in a list
},
childCount: cardList.length
)
)

How do I build objects of a class to use in ListView.builder?

I made a class of cars (has multiple strings such as price and brand.. etc) and I am trying to build a list of it so I can use it when building cards in a ListView but nothing shows up in the screen when I run the code.
I get an error that says vertical viewport was given unbounded height and my app does not show any cards (it does show anything else on the screen though)
My class:-
class cars {
String brand, type, model, color, price, pic;
cars(String b, String t, String m, String c, String p1, String p2) {
brand = b;
type = t;
model = m;
color = c;
price = p1;
pic = p2;
}
}
(page class)
class CHomePage extends State<CHP> {
int i = 0;
String price;
int selected = 0;
List<String> prices = ["Any", "<= 1200", "<= 1600", "<= 1800", "<= 2000"];
List<cars> myCars = new List();
void carsBuilder() {
cars c = new cars(
"Chevorlet", "Corvette Stingray", "2019", "Turqoise", "\$2100",
"assets/Images/corvette.jpg");
myCars.add(c);
c = new cars("Chevorlet", "Impala", "1967", "Black", "\$1900",
"assets/Images/impala.jpg");
myCars.add(c);
c = new cars(
"Dodge", "Challenger SRT Hellcat", "1967", "Dark Red", "\$2000",
"assets/Images/challenger.jpg");
myCars.add(c);
}
Widget buildPicker() {
return CupertinoPicker(
itemExtent: 50,
backgroundColor: CupertinoColors.white,
onSelectedItemChanged: (index) {
setState(() {
selected = index;
});
},
children: List<Widget>.generate(
prices.length,
(index) {
return Center(
child: Text(
prices[index],
style: TextStyle(fontSize: 18, color: Color(0xff469ABF)),
),
);
},
));
}
void incrementTab(index) {
setState(() {
i = index;
if (i == 1) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CAP()),
);
} else if (i == 2) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LP()),
);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CupertinoNavigationBar(
middle: Text(
'Home Page',
style: TextStyle(color: Color(0xff469ABF)),
),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Padding(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
"Choose Price Range: ",
style: TextStyle(fontSize: 18, color: Color(0xff469ABF)),
),
new CupertinoButton(
onPressed: () async {
await showModalBottomSheet<int>(
context: context,
builder: (BuildContext context) {
return buildPicker();
},
);
},
child: Text(prices[selected]),
),
],
),
),
new ListView.builder(
itemCount: myCars.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: <Widget>[
new ListTile(
leading: Icon(Icons.directions_car),
title: Text(myCars[index].type),
subtitle: Text(myCars[index].price),
),
new ButtonTheme.bar(
child: ButtonBar(
children: <Widget>[
new CupertinoButton(
child: Text("View More Details"),
onPressed: () {},
),
],
),
),
],
),
);
},
),
],
),
),
bottomNavigationBar: new Theme(
data: Theme.of(context).copyWith(
primaryColor: Colors.lightBlue,
textTheme: Theme.of(context)
.textTheme
.copyWith(caption: new TextStyle(color: Colors.black))),
child: new BottomNavigationBar(
items: [
BottomNavigationBarItem(
title: new Text('Home'),
icon: Icon(Icons.home),
),
BottomNavigationBarItem(
title: new Text('Account'),
icon: Icon(Icons.person),
),
BottomNavigationBarItem(
title: new Text('Logout'),
icon: Icon(Icons.directions_run),
),
],
currentIndex: i,
onTap: (index) {
incrementTab(index);
},
),
),
);
}
}
UPDATE:-
I added those 2 lines to my ListView.builder:-
scrollDirection: Axis.vertical,
shrinkWrap: true,
and put the parent column inside a listview and made the builder a child of it instead of being a child to the column..
My items show and i can scroll ONLY when i press somewhere specific.. other than that it doesnt scroll..
https://gyazo.com/f221fe659df002032ef7b56af5da4a56
where are you initializing the cars list
#override
void initState() {
// TODO: implement initState
super.initState();
carsBuilder();
}