Flutter Expandable in Dropdownmenu - flutter

I am trying to do a Dropdown menu with expandable Items inside.
I also got it working somehow but I am not sure if this the best way to do it.
I want a similar UI to this. A dropdown menu
that transforms into this.
What I did looks like this until now.
And on click this happens
So I got a somehow working Prototype. My issue is the icons like the dropdownmenu arrow icon, the "X" and "+" icons. Like for Example right now I am hiding the dropdown menu arrow because it overlaps with the "+" icon. Also the DropdownMenuItem is not a String but a PanleItem. so I can expand the list without opening the DropdownMenu.
I can't get it to work on the different stages.
I hope I can get some help here or someone can add some references to helpful Articles etc..
This is my Code till now.
import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';
class CustomExandableDropDown extends StatefulWidget {
#override
_CustomExandableDropDownState createState() =>
_CustomExandableDropDownState();
}
class _CustomExandableDropDownState extends State<CustomExandableDropDown> {
late String itemName;
late List<PanelItem> _data;
int currentIndex = 0;
List<String> items = ["first", "second", "third"];
#override
void initState() {
super.initState();
_data = generateItems(items.length);
itemName = _data.first.itemName;
}
List<PanelItem> generateItems(int numberOfItems) {
return List<PanelItem>.generate(numberOfItems, (int index) {
return PanelItem(
itemName: items[index],
);
});
}
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
decoration: BoxDecoration(
border: Border(
left: BorderSide(
width: 1,
color: Color(0xFFACACAC),
),
right: BorderSide(
width: 1,
color: Color(0xFFACACAC),
),
top: BorderSide(
width: 1,
color: Color(0xFFACACAC),
),
bottom: BorderSide(
width: 1,
color: Color(0xFFACACAC),
),
),
),
child: Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20.0),
child: Container(
child: DropdownButton<String>(
value: itemName,
isExpanded: true,
icon: Container(),
underline: Container(),
items: _data.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem<String>(
value: item.itemName,
child: ExpandablePanel(
theme: ExpandableThemeData(
hasIcon: false, tapHeaderToExpand: true),
header: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(item.itemName),
Icon(Icons.add),
],
),
collapsed: Container(),
expanded: Container(
width: MediaQuery.of(context).size.width,
color: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.itemName,
softWrap: true,
),
Text(
item.itemName,
softWrap: true,
),
Text(
item.itemName,
softWrap: true,
),
],
),
)),
);
}).toList(),
onChanged: (String? value) {
if (value != null) {
setState(() {
itemName = value;
});
}
},
),
),
),
),
);
}
}
class PanelItem {
PanelItem({
required this.itemName,
this.isExpanded = false,
});
String itemName;
bool isExpanded;
}

ExpansionTile and ExpansionPanel might just be what you are looking for with many example here

To achieve what you want to do you can use Expansion tile. I have something similar on a project which I'm currently working on. see if you can try and customize it for yourself:
//items is list of things which you want to include under each tile for example your //Rinnen Rinnenhalten .....
ExpansionTile(
trailing: Text(
'See all',
style: TextStyle(color: Colors.blue),
),
title: Text('Categories'),
children: [
Wrap(
children: [
for (var i in items)
Container(
width: 100,
height: 50,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BasedOnCats(i.toString())));
},
child: Card(
child: Center(
child: Text(i.toString()),
),
),
))
],
),
],
);

Related

DropDownButton doesn't work after using Navigator.push

I'm trying to create a clothes E-Shop app and I need the cart items to show the list of different colors for each product, I'm using a DropDownButton to show them, the slidable library to create the cart items, and a custom bottom bar. If I tap in the cart item to go to the product view and then go back to the cart pressing the back button, the dropdownbutton stops working, but if I go to the product through the bottom bar everything works.
class CartPage extends StatefulWidget {
const CartPage({Key? key}) : super(key: key);
#override
CartPageState createState() => CartPageState();
}
class CartPageState extends State<CartPage> {
List<String> dropDownValues = cart.itemList.keys.toList();
late String dropDownValueShow;
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
debugPrint('$dropDownValues');
dropDownValueShow = cart.itemList.isEmpty ? '' : dropDownValues[0];
return Scaffold(
bottomNavigationBar: CustomBottomNavBar(
1,
key: ValueKey(cart.itemList),
),
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.black,
title: const Text(
"Shopping Cart",
style: TextStyle(color: Colors.white, fontSize: 17),
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: cart.empty
? [
SizedBox(
width: 200,
height: 200,
child: Center(
child: Text(
"Empty Cart",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey.shade500,
fontSize: 20,
),
),
))
]
: [
Expanded(
child: AnimatedList(
scrollDirection: Axis.vertical,
initialItemCount: cart.itemList.length,
itemBuilder: (context, index, animation) {
return Slidable(
key: UniqueKey(),
actionPane: const SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
actions: const [],
secondaryActions: const [],
child: _cartItem(),
);
},
),
),
],
),
);
}
Widget _cartItem() {
return GestureDetector(
key: UniqueKey(),
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
const ProductView(),
transitionDuration: Duration.zero,
reverseTransitionDuration: Duration.zero,
),
).then((_) => setState(() {}));
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.shade200,
offset: const Offset(0, 2),
blurRadius: 6,
),
],
),
child: Row(
children: <Widget>[
Text('prod1'),
const SizedBox(
width: 10,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 10),
DropdownButton(
isExpanded: true,
value: dropDownValueShow,
icon: const Icon(Icons.arrow_drop_down),
items: cart.itemList.keys.toList().map((String value) {
return DropdownMenuItem(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropDownValueShow = newValue!;
});
},
),
const SizedBox(height: 10),
],
),
),
const SizedBox(
width: 10,
),
],
),
),
);
}
}
The whole code is in https://github.com/nicoacevedor/minimal.git

Flutter || Checkbox on hover doesn't give on tap cursor permission

I am working on dropdownmenu items where in the drop-down menu item there are several checkboxes but any of the checkboxes on hover don't give on tap cursor permission.
This is a very strange thing I found out as I have already used the checkbox before but this type of error I didn't receive.
I think maybe the problem is in dropdownmenu.
I have also included the video for better understanding of my problem.
my code :-
Container(
width: 160,
//margin: const EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.white),
child: ListTileTheme(
contentPadding: EdgeInsets.all(0),
dense: true,
horizontalTitleGap: 0.0,
minLeadingWidth: 0,
child: ExpansionTile(
iconColor: primaryBackgroundLightGrey,
title: Text(
listOFSelectedItem.isEmpty
? "Project type"
: listOFSelectedItem[0],
style: t5O40),
children: <Widget>[
Container(
height: 10,
color: primaryBackgroundLightGrey,
),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.listOFStrings.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
Container(
height: 10,
),
Container(
margin: const EdgeInsets.only(bottom: 8.0),
child: _ViewItem(
item: widget.listOFStrings[index],
selected: (val) {
selectedText = val;
if (listOFSelectedItem.contains(val)) {
listOFSelectedItem.remove(val);
} else {
listOFSelectedItem.add(val);
}
widget.selectedList(listOFSelectedItem);
setState(() {});
},
itemSelected: listOFSelectedItem
.contains(widget.listOFStrings[index])),
),
],
);
},
),
],
),
),
),
class _ViewItem extends StatelessWidget {
String item;
bool itemSelected;
final Function(String) selected;
_ViewItem(
{required this.item, required this.itemSelected, required this.selected});
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Padding(
padding: EdgeInsets.only(
left: size.width * .015,
),
child: Row(
children: [
SizedBox(
height: 2,
width: 2,
child: Checkbox(
value: itemSelected,
onChanged: (val) {
selected(item);
},
hoverColor: Colors.transparent,
checkColor: Colors.white,
activeColor: Colors.grey),
),
SizedBox(
width: size.width * .010,
),
Text(item, style: t3O60),
],
),
);
}
}
You can adapt the example to your own code
dropdownBuilder: _customDropDownExample,
popupItemBuilder: _customPopupItemBuilderExample,
Widget _customDropDownExample(
BuildContext context, UserModel? item, String itemDesignation) {
if (item == null) {
return Container();
}
return Container(
child: (item.avatar == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(),
title: Text("No item selected"),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
title: Text(item.name),
subtitle: Text(
item.createdAt.toString(),
),
),
);
After that
Widget _customPopupItemBuilderExample(
BuildContext context, UserModel item, bool isSelected) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 8),
decoration: !isSelected
? null
: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item.name),
subtitle: Text(item.createdAt.toString()),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
),
);
I am using this package https://pub.dev/packages/dropdown_button2
Multiselect Dropdown with Checkboxes
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}

How to customize the checkboxes, radio buttons and Rang slider in Flutters?

Hello Folks I am playing with Buttons to customize the buttons but I didn't find a way to approach the expected design. basically, I wanted to customize the 1) Multiple checkBoxes with Grey color Background and Black color Check Mark 2) RangeSlider Inactive bar with Grey color 3) Radio Button with black Color and I Want to unselect all, I understand that in Radio Button user cant Unselect all the buttons but I Want to unselect all with or without Radio Buttons(any different way is also fine) 4) same as 3rd point but Square Box with Grey color Background and Black color Check Mark. I attached a screenshot of my code and Expected design and also pasted my code. Please guys Help me to approach Expected Design, Please feel free to do comments for any clarity. Thanks in Advance.
What I want My expected Design My Result UI
Main File
import 'package:filters2/filter_screen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Dialog',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Filters'),
),
body: Center(
child: FlatButton(
onPressed: (){
filterBottomSheet();
},
color: Colors.green,
padding: EdgeInsets.fromLTRB(15, 15, 15, 15),
child: Text('Filters',style: TextStyle(fontSize: 16,color: Colors.white),),
),
),
);
}
filterBottomSheet(){
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: true,
builder: (BuildContext context){
return Filters();
}
);
}
}
Filters Class
import 'package:filters2/Fruit_model_class.dart';
import 'package:filters2/color_model_class.dart';
import 'package:filters2/mobile_model_class.dart';
import 'package:flutter/material.dart';
class Filters extends StatefulWidget {
#override
_FiltersState createState() => _FiltersState();
}
class _FiltersState extends State<Filters> {
/*--------MobileList-multiple checklist-------*/
List<MobileList> availableMobiles = [
MobileList(id: 0, companyName: "Google", model: "Pixel 6 Pro"),
MobileList(id: 1, companyName: "Apple", model: "Iphone Xr"),
MobileList(id: 2, companyName: "Xiaomi", model: "Redmi note 10"),
];
List<MobileList> selectedMobiles = [];
/*------Price Range Selection-RangeSlider--------*/
RangeValues _currentRangeValues = const RangeValues(40000, 80000);
int minPrice = 20000;
int maxPrice = 90000;
/*Radio--fruits*/
String radioItem1 = 'Mango';
int fruitGroupId = 0;
List<FruitsList> fList = [
FruitsList(id: 0, name: "Mango",),
FruitsList(id: 1, name: "Apple",),
FruitsList(id: 2, name: "Banana",),
FruitsList(id: 3, name: "Cherry",),
];
/*Radio--Colors*/
String radioItem2 = 'Red';
int? colorGroupId ;
List<ColorsList> cList = [
ColorsList(id: 0, name: "Blue",),
ColorsList(id: 1, name: "Red",),
ColorsList(id: 2, name: "Green",),
ColorsList(id: 3, name: "Yellow",),
];
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.85,
decoration: BoxDecoration(
//olor: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
)
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10,),
Container(
child: Text("Filter",style: TextStyle(color: Colors.black, fontSize: 24,fontWeight: FontWeight.bold),),
),
SizedBox(height: 10,),
Container(
child: Text("Select Mobiles (multiple selection)",style: TextStyle(color: Colors.black, fontSize: 20,fontWeight: FontWeight.bold),),
),
SizedBox(height: 10,),
Divider(),
Container(
child: Row(
children: [
Expanded(
flex:1,
child: ListView.builder(
shrinkWrap: true,
itemCount: availableMobiles.length,
itemBuilder: (context, playerIndex){
return CheckboxListTile(
controlAffinity: ListTileControlAffinity.trailing,
contentPadding: EdgeInsets.zero,
title:Text(availableMobiles[playerIndex].companyName),
value: selectedMobiles.contains(availableMobiles[playerIndex]),
onChanged: (value) {
if(selectedMobiles.contains(availableMobiles[playerIndex])){
selectedMobiles.remove(availableMobiles[playerIndex]);
}
else {
selectedMobiles.add(availableMobiles[playerIndex]);
}
setState(() {
});
}
);
}
),
),
Expanded(
flex: 2,
child:Container(
color: Colors.white ,
) ),
],
),
),
SizedBox(height: 10,),
Divider(),
Container(
child: Text("Year",style: TextStyle(color: Colors.black, fontSize: 20,fontWeight: FontWeight.bold),),
),
SizedBox(height: 10,),
Divider(),
Container(
child: Row(
//mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text("20000",style: TextStyle(color: Colors.black, fontSize: 20)),
),
Expanded(
child: RangeSlider(
values: _currentRangeValues,
min: minPrice.toDouble(),
max: maxPrice.toDouble(),
divisions: maxPrice - minPrice,
activeColor: Colors.black,
labels: RangeLabels(
_currentRangeValues.start.round().toString(),
_currentRangeValues.end.round().toString(),
),
onChanged: (RangeValues values) {
setState(() {
_currentRangeValues = values;
});
},
),
),
Align(
alignment: Alignment.centerRight,
child: Text("90000",style: TextStyle(color: Colors.black, fontSize: 20))),
],
),
),
SizedBox(height: 10,),
Divider(),
Container(
child: Row(
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Fruits (Single selection)",style: TextStyle(color: Colors.black, fontSize: 20,fontWeight: FontWeight.bold),),
Column(
children:
fList.map((data) => RadioListTile(
controlAffinity: ListTileControlAffinity.trailing,
contentPadding: EdgeInsets.zero,
title: Text("${data.name}"),
groupValue: fruitGroupId,
value: data.id,
onChanged: (val){
setState(() {
radioItem1 = data.name;
fruitGroupId = data.id;
});
},
)).toList(),
),
],
),
),
Expanded(
flex:2,
child: Container(
//width: 5,
color: Colors.white,
)),
],
),
),
Container(
child: Row(
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Colors",style: TextStyle(color: Colors.black, fontSize: 20,fontWeight: FontWeight.bold),),
Column(
children:
cList.map((colorData) => RadioListTile(
controlAffinity: ListTileControlAffinity.trailing,
contentPadding: EdgeInsets.zero,
title: Text("${colorData.name}"),
groupValue: colorGroupId,
value: colorData.id,
onChanged: (val){
setState(() {
radioItem2 = colorData.name;
colorGroupId = colorData.id;
});
},
)).toList(),
),
],
),
),
Expanded(
flex: 2,
child:Container(
color: Colors.white ,
) ),
],
),
),
],
),
),
);
}
}
mobile_model_class
class MobileList {
int id;
String companyName;
String model;
MobileList({required this.id, required this.companyName, required this.model});
}
Fruit_model_class
class MobileList {
int id;
String companyName;
String model;
MobileList({required this.id, required this.companyName, required this.model});
}
color_model_class
class ColorsList {
String name;
int id;
ColorsList({required this.name,required this.id});
}
To change color of checkbox you can use
Checkbox(
value: isCheck,
checkColor: Colors.black, // change color here
activeColor: Colors.grey,
onChanged: (bool value) {
setState(() {
isCheck = value;
});
}),
To change color of radio button try
Theme(
data: ThemeData(
//Change color here
unselectedWidgetColor: Colors.grey,
),
child: Row(
children: <Widget>[
Radio(),
Radio()
],
),
);
You can use SliderTheme class to customize your slider color and shape.
SliderTheme(
data: SliderThemeData(
this.trackHeight,
activeTrackColor:Colors.grey,
inactiveTrackColor:Colors.black,
thumbColor: Colors.green,
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 20)),
child: Slider(
value: _value,
onChanged: (val) {
_value = val;
setState(() {});
},
),
),
Hope the answer is helpful to you.

DropdownButton<List> using local data - Do not list items on the screen, only after hot reload

I'm new to the flutter and I don't know how to solve this problem.
I have a List with await method, but my screen does not await for the list to load to list, only when I update with the hot-reload, the screen works.
My async method
ListaRefeitorio? _selecione;
List<ListaRefeitorio> _refeitorios = <ListaRefeitorio>[];
RefeitorioController controller = new RefeitorioController();
#override
void initState() {
super.initState();
_listarRefeitorios();
}
My Screen
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarControleAcessoWidget("Refeitório"),
body: Column(
children: [
SizedBox(height: 30),
Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
border:
Border.all(color: AppColors.chartSecondary, width: 1),
borderRadius: BorderRadius.circular(15),
),
child: DropdownButton<ListaRefeitorio>(
hint: Text("Selecione Refeitório"),
dropdownColor: AppColors.white,
icon: Icon(Icons.arrow_drop_down),
iconSize: 36,
isExpanded: true,
underline: SizedBox(),
style: TextStyle(
color: AppColors.black,
fontSize: 20,
),
value: _selecione,
onChanged: (ListaRefeitorio? novoValor) {
setState(() {
_selecione = novoValor;
});
},
items: _refeitorios.map((ListaRefeitorio valueItem) {
return new DropdownMenuItem<ListaRefeitorio>(
value: valueItem,
child: new Text(valueItem.acessoPontoAcessoDescricao),
);
}).toList(),
),
),
),
),
),
Container(),
Expanded(
child: GridView.count(
crossAxisSpacing: 12,
mainAxisSpacing: 12,
crossAxisCount: 2,
children: [
Container(
child: SizedBox.expand(
child: FlatButton(
child: CardsWidget(
label: "Ler QR Code",
imagem: AppImages.scanQrCode,
),
onPressed: () {
scanQRCode();
},
),
),
),
Container(
child: SizedBox.expand(
child: FlatButton(
child: CardsWidget(
label: "Sincronizar Dados", imagem: AppImages.sync),
onPressed: () {
controller.sincronizar();
// RefeitorioService.listarRefeitorio();
},
),
),
),
SizedBox(height: 30),
Text("Resultado"),
Text(QRCode),
Text(DataHora),
Text(_selecione.toString()),
],
),
),
],
));
}
I've tried using the futurebuilder but I don't think that's my problem.
I don't know what to do anymore
I had the same issue with the DropDownButton list only displaying because of the Hot Reload refreshing the state.
When using a custom mapping of a List remember to use setState() in the method that populates the List with data (in my case it was pulling from Sqflite).
//This populate method would be called in either initstate or afterFirstLayout
populateDataList() {
await controller.getList().then((list) =>
setState(() {
_refeitorios = list;
})
);
}

Problem with List builder repeat the data when adding or removing item in the list

I'm new to flutter. When I adding new item or removing an item from the list, the list builder does update the list, but the problem is that the list builder also displaying the previous item list and showing new updated item list. So what I want to do is keeping the new updated item list instead of old item list.
class AlarmPage extends StatefulWidget {
final String title;
AlarmPage({Key key, this.title}) : super(key: key);
#override
_AlarmPageState createState() => _AlarmPageState();
}
class _AlarmPageState extends State<AlarmPage> {
String alarmName;
// Test Function
void _addAlarm() {
setState(() {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddAlarm()));
});
}
#override
void initState() {
super.initState();
Provider.of<AlarmsProvider>(context, listen: false).getLocalStorage();
}
#override
Widget build(BuildContext context) {
List<Widget> allWidgetsAlarms = List<Widget>();
return Consumer<AlarmsProvider>(builder: (context, alarmProviderItem, _) {
List<String> localAlarms = alarmProviderItem.alarms;
if (localAlarms != null) {
localAlarms.forEach((item) {
allWidgetsAlarms.add(
Stack(
children: <Widget>[
InkWell(
child: Container(
color: Color(0xff212121),
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
// Alarm Name & Title
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 2),
)),
child: Row(
children: <Widget>[
Icon(Icons.alarm, color: Colors.yellow),
SizedBox(width: 20.0),
Text('$item',
style: TextStyle(
color: Color(0xffC1C1C1),
fontSize: 15.0,
fontWeight: FontWeight.w900)),
SizedBox(height: 5),
],
),
),
SizedBox(height: 10),
// Alarm Time & Toggle Switch
Container(
child: Row(
children: <Widget>[
Text(
'Time',
style: TextStyle(
fontSize: 30, color: Colors.white),
),
SizedBox(width: 20),
Text(
'AM / PM',
style: TextStyle(
fontSize: 20, color: Color(0xffB5B5B5)),
),
SizedBox(width: 150),
Icon(Icons.switch_camera, color: Colors.yellow),
],
),
),
// Alarm Repeat
Container(
child: Row(children: <Widget>[
Text(
'Repeat',
style: TextStyle(
fontSize: 11, color: Color(0xff616161)),
),
Container(
child: DaySelector(
value: null,
onChange: (value) {},
color: Colors.yellow[400],
mode: DaySelector.modeFull,
),
),
]),
),
],
),
),
onLongPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddAlarm(item: item)));
},
),
SizedBox(height: 180),
],
),
);
print(item);
});
}
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text('Azy Alarm'),
centerTitle: true,
),
body: Container(
decoration: BoxDecoration(
image: const DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/background_image(dark).png')),
),
// child: ListView(children: allWidgetsAlarms),
child: ListView.builder(
itemCount: allWidgetsAlarms.length,
padding: const EdgeInsets.all(8.0),
itemBuilder: (BuildContext context, int index) {
return allWidgetsAlarms[index];
}),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.blue,
elevation: 0,
onPressed: _addAlarm,
),
);
});
}
}
So I think your issue is this line: allWidgetsAlarms.add( You construct allWidgetsAlarms in your builder, but the builder is not called again every time you Consumer rebuilds, hence it is just appending the new contents to the end of the list. To fix this, keep your original initialization of allWidgetsAlarms just at the top of the builder in your Consumer, add the following line:
allWidgetsAlarms = List<Widget>();
This will resert allWidgetsAlarms. Hope it helps!