Flutter Visibility widget not working third time - flutter

I have wrapped ListView.builder inside Visible widget, and the button for its visible property is in a ListTile widget with variable _currencyVisible.
The widget Visible works 2 times i.e. false/hidden(default), then changes to visible when clicked, and again hides on the second click, but it doesn't work after that. Printing on console _currencyVisible shows correct data.
Here's my code:
menuItems(BuildContext context) {
bool _currencyVisible = false;
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListView(
children: [
ListTile(
title: FutureBuilder<dynamic>(
future: getUserCurrencySymbol(),
builder:(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
return Text("Currency " + snapshot.data.toString());
}),
trailing: IconButton(
icon: Icon(Icons.refresh),
onPressed: () { setState(() { _currencyVisible = !_currencyVisible; }); },
),
),
Visibility(
visible: _currencyVisible,
child: ListView.builder(
shrinkWrap: true,
itemCount:
currency.allCurrenciesList.length,
itemBuilder: (context, index) {
for (Currency c in currency.allCurrenciesList) {
currency.allCurrenciesList.removeAt(0);
return Card(
child: ListTile(
title: Text(c.country),
subtitle: Text(c.shortCurrency),
trailing: Text(c.symbol),
onTap: () {
saveUserCurrency(c.country, context);
},
),
);
}
return Text("Not Null");
},
),
),
],
);
},
);
}

You are removing all of the data from your currency list. The widget is showing correctly, but there is no data to display.
Remove this line
currency.allCurrenciesList.removeAt(0);
Don't loop through the currencies in itemBuilder. Use index instead.
Visibility(
visible: _currencyVisible,
child: ListView.builder(
shrinkWrap: true,
itemCount: currency.allCurrenciesList.length,
itemBuilder: (context, index) {
final c = currency.allCurrenciesList[index];
return Card(
child: ListTile(
title: Text(.country),
subtitle: Text(c.shortCurrency),
trailing: Text(c.symbol),
onTap: () {
saveUserCurrency(c.country, context);
},
);
}
return Text("Not Null");
),
),

Related

Issue with statefulWidget unable to make desired changes

I am working on a statefulWidget and my purpose is to make sure that the next button is not clickable until an option (in this language is selected). However it doesn't seem to work, I also added Yaesin's(Someone who answered) answer to the code
ListView.builder(
itemCount: histoires.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
histoires[index].title,
style: TextStyle(color: Colors.pink),
),
trailing: IconButton(
icon: Icon(Icons.play_arrow),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) =>
AlertDialog(
content: Column(children: [
InkWell(
onTap: () {
_handleTap;
},
child: ListTile(
trailing: Icon(Icons
.flag_circle_rounded),
title: Text(
"French",
style: TextStyle(
color: Colors
.blueGrey),
))),
_active
? InkWell(
onTap: () {},
child: Image.asset(
"assets/nextactive.png",
height: height * 0.2,
width: width * 0.4),
)
: Image.asset(
"assets/nextinactive.png",
height: height * 0,
width: width * 0)
]),
));
});
}));
}),
To update dialog UI, you can use StatefulBuilder's setState
return StatefulBuilder(
builder: (context, setState) =>
AlertDialog(
content: Column(children: [
While using separate method, pass the StatefulBuilder's setState to the function. For your case, it will be
onPressed: () async {
await showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setStateSB) => AlertDialog(
content: Column(children: [
InkWell(
onTap: () {
_handleTap(setStateSB);
},
child: ListTile(
Also make sure to receive this setStateSB(renamed to avoid confusion with state's setState).
_handleTap(setStateSB){ ....
More about using StatefulBuilder
Since your in a Dialog, for setState to work, you need to wrap it with a StatefulBuilder.
You haven't included your full code, so I'm using this example taken from the docs:
await showDialog<void>(
context: context,
builder: (BuildContext context) {
int? selectedRadio = 0;
return AlertDialog(
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int? value) {
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
);
See also
A YouTube video by the Flutter team explaining StatefulBuilder

How to show ListView ind=side simpledialog

I am trying to show listview.builder inside simpledialog but it doesn't work
here is my code:
onTap: () {
return showDialog(
builder: (BuildContext context) {
return SimpleDialog(
title: Text('names'),
children: [
ListView.builder(
itemCount: names.length,
itemBuilder: ((context, index) {
return SimpleDialogOption(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(names[index].name),
);
}))
],
);
},
context: context);
},
change this line:
names[index].name
to this:
names[index]name
It won't work if you use the period between the values. But you should get an error for that.

ExpansionPanelList Scroll Issue

I have an ExpansionPanelList inside a ListView and I'm unable to get it to scroll when trying in the middle of the screen, though it will work on the edges. I've attached the code below. I'm guessing its the ExpansionPanelList that isn't letting me scroll but I'm not sure why because the items are inside a ListView as well.
I've taken a video of the issue https://drive.google.com/file/d/19zM7cfjshcN8OfEbRhvxIgmUp8sq1TP6/view?usp=sharing
_bodyBuilder() {
return
ListView(
shrinkWrap: true,
padding: EdgeInsets.all(15.0),
children: <Widget>[
ExpansionPanelList.radio(
initialOpenPanelValue: 2,
children: dateList.map<ExpansionPanelRadio>((DateTime date) {
return ExpansionPanelRadio(
canTapOnHeader: true,
value: date.day,
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: Text(DateFormat('dd/MM/yyyy').format(date)),
);
},
body: Container(
//child: ListView.separated(
child: ListView.builder(
shrinkWrap: true,
itemCount: cleanRecords
.where((Log) =>
DateTime.parse(DateFormat('yyyy-MM-dd')
.format(Log.time.toDateTime()))
.toString() ==
date.toString())
.toList()
.length,
itemBuilder: (context, index) {
final records = cleanRecords
.where((Log) =>
DateTime.parse(DateFormat('yyyy-MM-dd')
.format(Log.time.toDateTime()))
.toString() ==
date.toString())
.toList();
final schedule = records[index];
return ListTile(
title: Text(DateFormat('hh:mm').format(schedule.time.toDateTime())),
subtitle: Text(schedule.notes),
onTap: () => _updateRecord(schedule.parentID, schedule.id),
);
},
// separatorBuilder: (context, index) {
// return Divider();
// },
),
),
);
}).toList(),
)
],
);// ListTiles++
}

Flutter: When the snapshot is empty the widget disappears

I am trying to build a search list, the list is working fine but if the result is empty i need to show no data. I tried the following code but the widget holds for a second and then disappear
FutureBuilder(
future: getSearchedProducts(widget.searchString),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: Container(
child: Text('No Data Found.'),
),
);
} else {
return ListView.builder(
shrinkWrap: true,
itemCount: searchResult.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Image.network(searchResult[index].proThumbnail),
title: Text(searchResult[index].proName),
onTap: () {
print(searchResult[index].proName);
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ProductPage(prodid: searchResult[index].proId);
}));
},
),
);
});
}
})
Can anyone help me with this.
Thank you in advance.
I just write the code as below and it works.
FutureBuilder(
future: getSearchedProducts(widget.searchString),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('length of list ${searchResult.length}');
if (searchResult.length==0) {
return Center(
child: Text('No data'),
);
}
else if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
else {
return ListView.builder(
shrinkWrap: true,
itemCount: searchResult.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Image.network(searchResult[index].proThumbnail),
title: Text(searchResult[index].proName),
onTap: () {
print(searchResult[index].proName);
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ProductPage(prodid: searchResult[index].proId);
}));
},
),
);
});
}
}),
In your Code in Else part before - return ListView.builder- add the following code.
...
else {
if (searchResult.length == 0)
{
return Center(child: const Text('No Date'));
}
return ListView.builder .....

How to loop the PopupMenuItem in PopupMenuButton in Flutter?

I want to display values from my API in a PopupMenuItem in PopupMenuButton. I manage to display it but I want it to be dynamic. Currently, I hard-coded the index of each item because it seems that I cannot do looping inside PopupMenuButton.
`Widget _simplePopup4() => PopupMenuButton<int>(
child: Icon(Icons.arrow_drop_down, color: Colors.orangeAccent),
offset: Offset(0, 100),
itemBuilder: (context) => [
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[1].title); //index 1
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[2].title); //index 2
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[3].title); //index 3
}
}
return CircularProgressIndicator();
})),
),
],
);`
//First attempt which gives error: RenderShrinkWrappingViewport does not support returning intrinsic dimensions.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.setTitle.length,
itemBuilder:
(BuildContext context, int index) {
return Text(snapshot.data.setTitle[index].title);
});
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
//Second attempt which gives error: Another exception was thrown: A RenderFlex overflowed by 85 pixels on the bottom.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final listTitle = <Widget>[];
for (var i = 0;
i < snapshot.data.setTitle.length;
i++) {
listTitle.add(SingleChildScrollView(
scrollDirection: Axis.vertical,
child: InkWell(
child:
Text(snapshot.data.setTitle[i].title),
)));
}
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Column(children: listTitle);
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
From the screenshot, only one item are clearly displayed which is "MR" while the other item (before item "MR") are displayed in half. Meanwhile, the rest of the item (after item "MR") being replaced with error message.
The screenshot of the second attempt error
The cause of the RenderFlex error is because the child Widget expands beyond the parent Widget. What you can do here is fetch the List of PopupMenu items prior to rendering the PopupMenuButton. With this approach, the List items is ready prior to clicking the PopupMenuButton.