How to pass parameters in Flutter ListView - flutter

i want to pass list of title and description in my list view, i can pass in list view builder, but i don't how to pass in list view.
i want to pass entries array in ListView. without typing each entry i want to show everything in array on cards.
Widget build(BuildContext context) {
final List<String> entries= <String> ['Entry one','Entry Two','Entry Three','Entry one','Entry Two','Entry Three','Entry one','Entry Two','Entry Three','Entry one','Entry Two','Entry Three'];
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: ListView(
children: const <Widget>[
Card(
child: ListTile(
leading: FlutterLogo(size: 40.0),
title: Text('all entries one by one'),
subtitle: Text(
'subtitle'
),
trailing: Icon(Icons.favorite),
isThreeLine: true,
),
),
],
)
);
}

You can use ListView.builder() for this. Here is an example.
class TestPage extends StatelessWidget {
final List<String> entries = <String>[
'Entry one',
'Entry Two',
'Entry Three',
'Entry one',
'Entry Two',
'Entry Three',
'Entry one',
'Entry Two',
'Entry Three',
'Entry one',
'Entry Two',
'Entry Three'
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: Container(
height: 500,
child: ListView.builder(
itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(entries[index]),
subtitle: Text('subtitle'),
trailing: Icon(Icons.favorite),
isThreeLine: true,
),
);
},
),
),
);
}
}

If you already have array of title and description using the ListView.builder() is the best option here. First make a class for your title and description:
class Info{
String title;
String description;
Info(this.title, this.description);
}
Now create an array of this info class List<Info> _myInfo and populate it with your data. Now you can create your list view like this:
ListView.builder(
itemCount: _myInfo.length,
builder: (context, index) {
return _createCard(index);
}
);
Now you can separate your card creation here like this:
Widget _createCard(int index){
return Card(
child: ListTile(
leading: FlutterLogo(size: 40.0),
//here your title will be create from array for each new item
title: Text(_myInfo[index].title),
subtitle: Text(
'subtitle'
),
trailing: Icon(Icons.favorite),
isThreeLine: true,
),
),
}
Code might contain syntax error feel free to ask if you face any problem

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

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 [])));
}
}

Flutter: how to use DropDownButton?

i'm trying to build a DropdownButton widget of multiple elements, but I'm miserably failing even if I read multiple tutorials on the Internet.
How can I go about creating a simple DropdownButton of 4 elements ?
Thanks for your time
Here's what I tried:
import 'package:flutter/material.dart';
class ForgotPassScreen extends StatefulWidget {
#override
_ForgotPassScreenState createState() => _ForgotPassScreenState();
}
class _ForgotPassScreenState extends State<ForgotPassScreen> {
int _value = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dropdown Button"),
),
body: Container(
padding: EdgeInsets.all(20.0),
child: DropdownButton(
value: _value,
items: [
DropdownMenuItem(
child: Text("Item 0"),
value: 0,
),
DropdownMenuItem(
child: Text("First Item"),
value: 1,
),
DropdownMenuItem(
child: Text("Second Item"),
value: 2,
),
DropdownMenuItem(
child: Text("Third Item"),
value: 3,
),
DropdownMenuItem(
child: Text("Fourth Item"),
value: 4,
)
],
onChanged: (value) {
setState(() {
_value = value;
});
}),
));
}
}
So this code has basically 3 parts to it. First is the object which stores the icon and the title. The second is the list of these objects, you can have as many as you want. And third is the button itself which constructs the boxes
OBJECT
class Choice {
const Choice({this.title, this.icon});
final String title;
final IconData icon;
}
LIST
List<Choice> choices = <Choice>[
const Choice(title: 'Profile', icon: Icons.account_circle),
const Choice(title:"Log in", icon: Icons.exit_to_app),
]
POPUP BUTTON
PopupMenuButton<Choice>(
color:Colors.white,
onSelected: onItemMenuPress,
itemBuilder: (BuildContext context) {
return choices.map((Choice choice) {
return PopupMenuItem<Choice>(
value: choice,
child: Row(
children: <Widget>[
Icon(
choice.icon,
color:Colors.black
),
Container(
width: 10.0,
),
Text(
choice.title,
style: TextStyle(),
),
],
));
}).toList();
},
)
This is the best way to create the button as you can modify it without having to change every single piece of code

Understanding ListView.builder

Okay, so I think I am stuck with flutter builder a little bit.
I've created simple app, just to make my question easier:
I have a data class:
class DataLists {
List<ListTile> lists = [
ListTile(
leading: Text('Tile Leading 1'),
title: Text('Tile Title 1'),
subtitle: Text('Tile Subtitle 1'),
trailing: Text('Tile Trailing 1'),
),
ListTile(
leading: Text('Tile Leading 2'),
title: Text('Tile Title 2'),
subtitle: Text('Tile Subtitle 2'),
trailing: Text('Tile Trailing 2'),
),
ListTile(
leading: Text('Tile Leading 3'),
title: Text('Tile Title 3'),
subtitle: Text('Tile Subtitle 3'),
trailing: Text('Tile Trailing 3'),
),
ListTile(
leading: Text('Tile Leading 4'),
title: Text('Tile Title 4'),
subtitle: Text('Tile Subtitle 4'),
trailing: Text('Tile Trailing 4'),
),
ListTile(
leading: Text('Tile Leading 5'),
title: Text('Tile Title 5'),
subtitle: Text('Tile Subtitle 5'),
trailing: Text('Tile Trailing 5'),
),
];
}
And main dart file:
import 'package:flutter/material.dart';
import 'package:learning/data.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: TestTile(),
);
}
}
class TestTile extends StatefulWidget {
#override
_TestTileState createState() => _TestTileState();
}
class _TestTileState extends State<TestTile> {
DataLists dataLists = DataLists();
TextEditingController leadingController = TextEditingController();
TextEditingController titleController = TextEditingController();
TextEditingController subtitleController = TextEditingController();
TextEditingController trailingController = TextEditingController();
Future<String> createDialog(BuildContext context) {
return showDialog(context: context, builder: (context) {
return SimpleDialog(
title: Text('Input data: '),
children: [
TextField(
controller: leadingController,
),
TextField(
controller: titleController,
),
TextField(
controller: subtitleController,
),
TextField(
controller: trailingController,
),
MaterialButton(
child: Text('Submit'),
onPressed: () {
Navigator.of(context).pop(leadingController.text);
setState(() {
List<ListTile> tempList = dataLists.lists;
if (titleController.text.isNotEmpty && leadingController.text.isNotEmpty && subtitleController.text.isNotEmpty && trailingController.text.isNotEmpty) {
tempList.add(
ListTile(
leading: Text(leadingController.text),
title: Text(titleController.text),
subtitle: Text(subtitleController.text),
trailing: Text(trailingController.text),
),
);
dataLists.lists = tempList;
} else {
print('Null values');
}
leadingController.clear();
titleController.clear();
subtitleController.clear();
trailingController.clear();
});
},
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test Tile'),
),
body: Container(
child: SafeArea(
child: ListView(
children: <ListTile>[
for (ListTile e in dataLists.lists)
e
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
createDialog(context);
setState(() {
});
},
child: Icon(Icons.add),
backgroundColor: Colors.blue,
),
);
}
}
The problem is: I cannot make it work in other way. Can someone change my implementation to a ListView.builder? I am stuck a little bit :(
Key goal:
Idea:
Click on a button -> form appear -> after you press a submit button list is updated instantly
I'll add a delete function later, just learning docs, nothing more.
Can someone review my code and, if no one mind, try to rewrite the same idea, but using ListView.builder?
I've tried several times, but cannot get properties correctly from the form, and update listtile using builder, need help
Cheers!
ListView.builder requires a static height, so keep a track on that one. Now, coming to the question, that you want to use ListView.builder. You can do via this
Container(
height: give_your_height,
child: ListView.builder(
shrinkWrap: true,
itemCount: dataLists.lists.length,
itemBuilder: (context, index) {
return dataLists.lists[index];
}
)
)
Try this, it may solve your issue.
ListView(
children: [
for (ListTile e in dataLists.lists)
Card(child: e)
],
),
or with ListView.builder()
ListView.builder(
itemCount: dataLists.lists.length,
itemBuilder: (context, index) {
return dataLists.lists[index];
},
);
Further Reference: https://api.flutter.dev/flutter/material/ListTile-class.html

RangeError : RangeError(index) : invalid value : only valid is 0: 3

I display the products available in my basket in this Screen Basket which works very well. I use a dismissible to be able to delete an item from my basket. And I often get the error from time to time: RangeError: RangeError (index): invalid value: only valid is 0: 3. What to do please?
Here is the interface of my basket. Basket_Screen. can flutter clean be the best solution? I'm afraid to try it. What exactly does flutter clean do? I need a solution please
class PanierScreen extends StatefulWidget {
#override
_PanierScreenState createState() => _PanierScreenState();
}
class _PanierScreenState extends State<PanierScreen> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
List<Produit> produits = Provider.of<Panier>(context).produits ;
Panier _panier = Provider.of<Panier>(context, listen : false);
super.build(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Panier",
home: Scaffold(
appBar: AppBar(
title: Text("Panier"),
centerTitle: true,
),
body: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(child: ListView.separated(
itemCount: produits.length,
itemBuilder: (BuildContext context, int index) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
background: new Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Icon(
Icons.delete, color: Colors.white,),
),
Spacer(),
Text("Supprimer", style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),)
],
),
color: Colors.red,
),
onDismissed: (direction) {
// _panier.retirerProduit(produits[index]);
produits.removeAt(index);
print(produits.length);
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text("Produit supprimé du panier"),
duration: Duration(seconds: 3),)); },
child: Card (
child: ListTile(
leading: CircleAvatar(
child: FittedBox(
child: Text("${produits[index].prixvente} FCFA"),
),
),
title: Text("${produits[index].designation}".toUpperCase(), style: TextStyle(fontWeight: FontWeight.bold),),
subtitle: Text("Total : ${produits[index].quantite_vendue * produits[index].prixvente} FCFA", style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red[300]), ),
trailing: Text("${produits[index].quantite_vendue.toString()} x", style: TextStyle(fontWeight: FontWeight.bold),),
),
),
);
},
separatorBuilder: (BuildContext context, int index) => Divider(),
))
],
),
),
);
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
flutter clean will rebuild the /build folder (Flutter's Build Cache). It's a safe command to run, but I don't think it has anything to do with your problem.
Seems like you're removing and item at some index from your List produits them trying to access it latter in the code.