Can't display image when list is empty in Flutter - flutter

I am displaying an image in my code when the list is empty. I am using firebase to fetch data and store it in the list since there is no data stored yet so the list is empty initially. But it is not displaying the image on empty condition
Code:
// tab bar view her
Expanded(
child: TabBarView(
controller: _tabController,
children: [
Container(
padding: EdgeInsets.only(right: 32, left: 32),
child: Medicine(),
),
// second tab bar view widget
Container(
padding: EdgeInsets.only(right: 32, left: 32),
child: MedHistory(),
),
],
),
),
],
),
Widget Medicine() {
print("MedicineList ${med_list.length}");
if(med_list.isEmpty) {
noMedicine();
}else {
ListView.separated(
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.symmetric(vertical: 11, horizontal: 20),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
return MedicinesList(
med_list[index].userSdate,
med_list[index].userReminder,
med_list[index].userEdate,
med_list[index].userFreq,
med_list[index].userDosage,
med_list[index].userMed,
med_list[index].key);
},
separatorBuilder: (_, __) => Container(),
itemCount: med_list.length);
}
}
Widget noMedicine() {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(("assets/images/Medicine-amico.png")),
SizedBox(
height: 20,
),
Text(
'Hurray! You don\'t have any pending medicines to take!',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.w600,
fontSize: 14,
color: const Color(0x78000000),
height: 1.4285714285714286,
),
textAlign: TextAlign.center,
),
],
),
);
}
My screen should display this in case the list is empty:
Kindly help me out in solving the problem, Thank you

Can you try using med_list.isEmpty instead of med_list.length == 0 in your if check?
Edit: also make the list empty through List<MedicineList> med_list = []; or List<MedicineList> med_list = <MedicineList>[]; instead of List<MedicineList> med_list = List();.
Edit 2: The issue was that widgets were made using Widget name = {}. A widget has to be a class which extends either Stateless or Stateful. It also has to have an #override build(BuildContext context) {} fucntion. Please see comments for more details.

By using the condition of checking if list is empty or not inside TabView would make it and will display the image as well:
Expanded(
child: TabBarView(
controller: _tabController,
children: <Widget>[
med_list.length == 0
? noMedicine()
: ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
return MedicinesList(
med_list[index].userSdate,
med_list[index].userReminder,
med_list[index].userEdate,
med_list[index].userFreq,
med_list[index].userDosage,
med_list[index].userMed,
med_list[index].key);
},
separatorBuilder: (_, __) => Container(),
itemCount: med_list.length,
),
// second tab bar view widget
Container(
padding: EdgeInsets.only(right: 32, left: 32),
child: MedHistory(),
),
],
),
),

Related

Prevent ExpansionTile from expanding beyond viewport/screen

I'm trying to build a screen where there are two lists containing items fetched from an API. I want to use an ExpansionTile for each list to present the data to the user so that the user can decide which data he wants to access.
As the data comes from an API it might be that the data present in a list is more than what fits on the screen, thus I'd like the ExpansionTile to be scrollable inside (I don't want the page to be scrollable but the ExpansionTile Widget!!!)
Currently if I expand the ExpansionTile this is the problem I'm facing if there's too much data to display within the ExpansionTile:
However, I'd like the UI to look something like this:
How can I limit the ExpansionTiles to the boundaries of the screen and force them to be scrollable if they overflow? Currently I use a ListView.builder and also tried nesting it inside a SingleChildScrollView but that didn't help.
This is how my code for this screen looks right now (which is only the inner part wrapped between the AppBar and BottomNavigationBar because they belong to the screen providing the PageView):
class MembershipScreen extends StatefulWidget {
const MembershipScreen({Key? key}) : super(key: key);
#override
_MembershipScreenState createState() => _MembershipScreenState();
}
class _MembershipScreenState extends State<MembershipScreen> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Center(
child: Container(
constraints: BoxConstraints(maxWidth: 500),
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Clubs',
style: kHeadingStyle,
),
SizedBox(
height: 20,
),
_buildMyClubs(),
SizedBox(
height: 20,
),
_buildAllClubs(),
],
),
),
),
);
}
Widget _buildMyClubs() {
return Container(
decoration: BoxDecoration(
color: kPrimarySwatch,
border: Border.all(
color: kSecondarySwatch,
width: 2,
),
borderRadius: BorderRadius.circular(25)
),
child: Theme(
data: ThemeData().copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
initiallyExpanded: false,
title: Text("My Clubs", style: kLabelStyle,),
children: [
SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: 4,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text("Test", style: kHintTextStyle,),
);
},
),
)
],
),
),
);
}
Widget _buildAllClubs() {
return Container(
decoration: BoxDecoration(
color: kPrimarySwatch,
border: Border.all(
color: kSecondarySwatch,
width: 2,
),
borderRadius: BorderRadius.circular(25)
),
child: Theme(
data: ThemeData().copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
initiallyExpanded: false,
title: Text("All Clubs", style: kLabelStyle,),
children: [
SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: 8,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text("Test", style: kHintTextStyle,),
);
},
),
)
],
),
),
);
}
}
I'd really appreciate any help as I don't have any idea what I could try to solve this issue now. If anything is still unclear please let me know and I will try to provide the missing information asap.

how to style the Horizontal scroll bar according to this UI flutter

This is my code for the horizontal scrollbar. how to style this according to given UI. where and how I should add styles on this code. the code is showing how I placed the scroll bar in my home. dart. need suggestions to add styles.
home.dart.
body: ListView(
children: [
buildSearchInput(),
Padding(
padding: const EdgeInsets.only(top: 40, left: 20, right: 20),
child: Column(
children: [
SizedBox(
height: kToolbarHeight,
child: ListView(
scrollDirection: Axis.horizontal,
children: List.generate(4, (index) => Text("item $index")),
),
),
],
),
)
,
You can use Container with StadiumBorder to decorate them and using ListView.separated to have space between items.
final List<String> data = ["item A", "Item Number 2", "new One"];
Widget itemW({
required String text,
required Color bgcolor,
required Color textColor,
}) {
return Container(
padding: const EdgeInsets.all(16),
alignment: Alignment.center,
decoration: ShapeDecoration(
shape: const StadiumBorder(),
color: bgcolor,
),
child: Text(
text,
style: TextStyle(color: textColor),
),
);
}
....
ListView.separated(
itemCount: data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) =>
itemW(color: Colors.cyanAccent,
bgcolor: Colors.cyanAccent,
text: data[index]),
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
),

Wrapping a ListView Builder Output with small bubble text boxes that wrap

I'm trying to produce a wrapping list of button text boxes. I cannot find a way to wrap this properly. I've included 2 images, one of the current output and another of the desired output.
return Wrap(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: _filteredHashTags.isEmpty
? hashTagWigetsList.length
: _filteredHashTags.length,
itemBuilder: (context, index) {
return _buildHashTagList(hashTagWigetsList[index]);
}),
This is what is looks like:
This is what I'd like it to look like:
Demo
final items = List.generate(4, (i) => " item $i"); // response
return Scaffold(
body: Column(
children: [
Container(
child: Text("Search Field"),
),
Wrap(
children: [
...items.map(
(e) => Padding(
padding: EdgeInsets.all(4),
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text(e)),
),
),
///or
...List.generate(
items.length,
(index) => Text(
items[index],
style: TextStyle(
backgroundColor: Colors.blue,
),
),
)
],
)
],
));
}

Problem adding widget to GridView with button and scroll

At first I had a Wrap that by clicking on the "add" button would add a new card to the Wrap. Then I changed the Wrap to GridView so that I could add scrolling. However, now when I press the button nothing shows on the device, but if I change GridView back to a Wrap and hot reload, the cards show up? I'm not sure what's wrong.
Also I can't scroll, I know I'm doing something wrong, but I have no idea what.
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
List<Widget> cards = [];
dynamic addReusableCard (String activity, int goal, double elapsed){
return cards.add(ReusableCard(activityText: activity, activityLength: goal, activityTimeElapsed: elapsed,));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text('TIME CARDS',
style: TextStyle(
fontSize: 20.0,
letterSpacing: 5.0,
),),
Text('You\'re awake for a total of 16h',
style: TextStyle(
fontSize: 16.0,
fontStyle: FontStyle.italic,
),),
Expanded(
flex: 9,
child: GridView.count(
crossAxisCount: 2,
childAspectRatio: (175.0 / 220.0),
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
children: cards
),
),
Padding(
padding: const EdgeInsets.all(18.0),
child: Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: (){
setState(() {
addReusableCard('reading', 2, 0.3);
});
},
backgroundColor: kAccentColor,
elevation: 0.0,
child: Icon(Icons.add),
),
),
),
],
),
),
),
);
}
}
Thanks in advance
For a dynamic list length you should use gridView.builder()
Here is the relevant code:
Expanded(
flex: 9,
child: GridView.builder(
itemCount: cards.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
itemBuilder: (BuildContext context, int index) {
return cards[index];
}
)
),

Flutter How to Display a List of Widgets in a Container

So in my app, I am building a list of widgets, which is basically just a container with text in it.
I am doing this for a variety of reasons, but basically here is where I am having the problem.
I can view this list in a ListView.Builder, but I do not want to view them that way. I want to be able to view them in a container. Then wrap down the container as items get added.
Below is a mock up of what I am trying to do.
Right now my page looks like this.
body: Column(children: <Widget>[
Expanded(
flex: 3,
child: Container(
width: MediaQuery.of(context).size.width*0.8,
child: Row(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: hashList.length,
itemBuilder: (context, index){
return Container(
child: hashList[index],
);
}),
)
],
),
),
),
Expanded(
flex: 6,
child: Container(
color: Colors.black,
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return Tag(
callback: (list) => setState(() => hashList = list),
tag: snapshot[index].data["title"],
list: hashList,
id: index,
);
},
)
))]),
And the Tag Widget adds to the list with the following.
void _handleOnPressed() {
setState(() {
isSelected = !isSelected;
isSelected
? _animationController.forward()
: _animationController.reverse();
isSelected ? widget.list.add(
Container(
padding: EdgeInsets.all(10),
height: 45,
child: Text(widget.tag, style: TextStyle(color: Color(0xffff9900), fontSize: 20, fontFamily: 'Dokyo'),),
decoration: BoxDecoration(
border: Border.all(color: Color(0xffff9900),),
borderRadius: BorderRadius.circular(10))
)): widget.list.removeAt(widget.id);
});
}
}
Adding the list to a listview, I can do, but it is not the desired affect.
I have no clue how to do what I am looking for and I am completely lost.
Try and add shrinkWrap to the ListView Builder
child: ListView.builder(shrinkWrap:true, <-- this
.... # then continue your logic