How to put a ListView.builder in a Drawer? - flutter

I'm trying to make a dynamic menu (via a json file). When I put my code in the body it's working fine. But when I put it in my Drawer, the drawer is blank, even my DrawerHeader disappear.
My code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My App'),
backgroundColor: Colors.green,
),
body: ListView.builder( // <---------- WORKING
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, i) {
return new ListTile(
title: new Text(data[i]["title"]),
);
}),
drawer: Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
Container(
height: 85.0,
child: DrawerHeader(
child: Text(
'Categories',
style: new TextStyle(fontSize: 18.0, color: Colors.white),
),
decoration: BoxDecoration(
color: Colors.green,
),
),
),
ListView.builder( // <---------- NOT WORKING
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, i) {
return new ListTile(
title: new Text(data[i]["title"]),
);
})
],
),
),
);
}
full code

Your ListView.builder widget needs to be inside a widget with a fixed height.
You can set it inside a Container:
Container(
height: double.maxFinite,
child: ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, i) {
return new ListTile(
title: new Text(data[i]["title"]),
);
}))

Related

How to add multiple child inside a Scaffold

I want to add a button, below the listview to navigate to the next page! But I am unsure of the layout.
#override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
title:const Text("Welcome"),
centerTitle: true,
),
body:Center(
child:SizedBox(
child:ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)
child: TextButton(onPressed: onPressed, child: child) // Where am i suppose to add this?
)
)
);
I am unsure of the layout! Any help will be greatly appreciated!
Simply wrap the ListView with a Column:
#override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
title:const Text("Welcome"),
centerTitle: true,
),
body:Column(
children: [
Center(
child:SizedBox(
child:ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
)
child: TextButton(onPressed: onPressed, child: child) // Where am i suppose to add this?
)
),
],
);
After you done this, you can add as many widgets as you want.
Hope it helps!

how can I add some Text or TextField or something above that ListTile in body?

ListTile is the only thing what can be in body here. idk why.
I cant create anythin, even Text, in body now.
Here is my code, it seems that I don't know correct structure of a project.
That's how app should look like:
https://vk.com/im?peers=420186915_-51497091_c21_-104755778_401520442_186961199_c1_188402691_596510656_312494247_493063710_171187154_161887710_c4_160881882_c2_-157369801&sel=221808173&z=photo478522815_457252372%2Fmail269045
I've made ListVies with Cards but cant add search area aabove
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: events.length,
itemBuilder: (_, index) => Card(
elevation: 10,
shadowColor: Colors.white,
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: ListTile(
title: Text(
events[index].name,
style: TextStyle(
fontSize: 13,
),
),
subtitle: Text(
"${events[index].spot} ${events[index].price}",
style: TextStyle(
fontSize: 20.0,
),
),
//isThreeLine: true,
leading: SvgPicture.asset("assets/images/car_icon.svg"),
onTap: () => print("${events[index].name} - tap"),
),
)
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemCount: 5,
itemBuilder: (_,i){
return Column(
children: [
Text("Ici Text or TextField $i"),
ListTile(title: Text("Ici ListTile $i",)
)],
);
},
)
);
}
You can wrap your listview with a column, something like this:
Container{
Column{
......

How to add dynamic content in ExpansionTile on drawer?

I need to add a ListViewBuilder in ExpansionTile. The expansion tile in the left side drawer. Im new in flutter, i dont know how to add this ? Please help me to fix this ?
drawer: Drawer(
child: Container(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(......),
ListTile(......),
ListTile(......),
ExpansionTile(
title: Text(
'Game Rules',
style: TextStyle(color: Colors.white),
),
leading: new IconButton(
icon: new Icon(
Icons.wb_iridescent,
color: Colors.white,
),
),
children: <Widget>[
ListView.builder(
itemCount: _rules.length,
itemBuilder: (context, index) {
return Text(_rules[index]['category']);
})
],
),
]
In your ListView.builder - add - shrinkWrap: true,
ListView.builder(
shrinkWrap: true, // Add this
itemCount: _rules.length,
// itemCount: 10,
itemBuilder: (context, index) {
return Text(_rules[index]['category']);
// return Text('$index');
})

Flutter: Help building a scrollable ListView

item1, item2, item3 are all lists and i am trying to build a list view with all the items that each list holds, where all this three listview builders would take as much place as they need, lets say that item1 has 20 items in it and it will take 20 rows, and item2 has 25 etc. When i try to use a row and listview.builder it gives me an error.
What I am trying to do:
body: Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.item1[index]),
);
},
itemCount: widget.item1 == null ? 0 : widget.item1.length,
),
],
),
],
),
),
Among a huge list of crash report:
flutter: Another exception was thrown: NoSuchMethodError: The method '<=' was called on null.
flutter: Another exception was thrown: NoSuchMethodError: The getter 'visible' was called on null.
The problem is that the only way I know is to make it with an Expanded, and it will divide the screen in three and make equal space or i can manipulate with flex, but this is not what i want.
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.item1[index]),
);
},
itemCount: widget.item1 == null ? 0 : widget.item1.length,
),
),
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.item2[index]),
);
},
itemCount: widget.item2 == null ? 0 : widget.item2.length,
),
),
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(widget.item3[index]),
);
},
itemCount: widget.item3 == null ? 0 : widget.item3.length,
),
),
],
),
),
This is what I was talking about, a List using SingleChildScrollView and Column, you can also do the same with Slivers
A sample I made for you:
final List<String> item1 = List.generate(5, (val) => "item1 $val");
final List<String> item2 = List.generate(5, (val) => "item2 $val");
final List<String> item3 = List.generate(5, (val) => "item3 $val");
#override
Widget build(BuildContext context) {
final items = <Widget>[];
for (String i1 in item1) {
items.add(ListTile(
title: Text(i1),
));
}
for (String i2 in item2) {
items.add(ListTile(
title: Text(
i2,
style: TextStyle(
color: Colors.red,
),
),
));
}
for (String i3 in item3) {
items.add(ListTile(
title: Text(
i3,
style: TextStyle(
color: Colors.blue,
),
),
));
}
return Scaffold(
body: Container(
child: SingleChildScrollView(
child: Column(
children: items,
),
),
),
);
}
}
Another way using ListView.builder :
return Scaffold(
body: Container(
child: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(item1[index]),
);
},
itemCount: item1.length,
),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
item2[index],
style: TextStyle(
color: Colors.red,
),
),
);
},
itemCount: item2.length,
),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(item3[index]),
);
},
itemCount: item3.length,
),
],
),
),
),
);
}
Don't forget to check this awesome article about Slivers by Emily Fortuna (Flutter team)
https://medium.com/flutter/slivers-demystified-6ff68ab0296f

How to implement Nested ListView in Flutter?

What is the preferred way to achieve a nested ListView, or in other words, ListView Widgets that could be included within a scrollable parent?
Imagine a "Reports" page, where a section is an itemized list.
For child ListView, use that parameter:
shrinkWrap: true,
physics: ClampingScrollPhysics(),
Adding physics: ClampingScrollPhysics() and shrinkWrap: true did the trick for me.
sample code:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 123,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Parent'),
ListView.builder(
itemCount: 2,
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Text('Child');
}),
],
);
}),
)
],
),
);
}
If you want to have the inner ListView be scrollable independently of the main scroll view, you should use NestedScrollView. Otherwise, use a CustomScrollView.
Here is some code illustrating the NestedScrollView approach.
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
new SliverAppBar(
pinned: true,
title: new Text('Flutter Demo'),
),
];
},
body: new Column(
children: <Widget>[
new FlutterLogo(size: 100.0, colors: Colors.purple),
new Container(
height: 300.0,
child: new ListView.builder(
itemCount: 60,
itemBuilder: (BuildContext context, int index) {
return new Text('Item $index');
},
),
),
new FlutterLogo(size: 100.0, colors: Colors.orange),
],
),
),
);
}
}
For inner Listview I have just added below code and it solved for me
shrinkWrap: true,
physics: ScrollPhysics(),
Screenshot:
Code:
var _container = Container(
height: 200,
color: Colors.blue,
margin: EdgeInsets.symmetric(vertical: 10),
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ListView")),
body: Padding(
padding: const EdgeInsets.all(40.0),
child: ListView( // parent ListView
children: <Widget>[
_container,
_container,
Container(
height: 200, // give it a fixed height constraint
color: Colors.teal,
// child ListView
child: ListView.builder(itemBuilder: (_, i) => ListTile(title: Text("Item ${i}"))),
),
_container,
_container,
_container,
],
),
),
);
}
Thanks to Serdar Polat:
ListView.builder( // outer ListView
itemCount: 4,
itemBuilder: (_, index) {
return Column(
children: [
Container(
color: Colors.blue,
alignment: Alignment.center,
child: Text('Header $index'),
),
ListView.builder( // inner ListView
shrinkWrap: true, // 1st add
physics: ClampingScrollPhysics(), // 2nd add
itemCount: 10,
itemBuilder: (_, index) => ListTile(title: Text('Item $index')),
)
],
);
},
)
shrinkWrap to wrap your content and ClampingScrollPhysics to use the parent scroll
ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: yourList.length,
itemBuilder: (context, index) => YourWidget(items[index]),
),
I use this:
scrollController.addListener(onScroll);
void onScroll(){
if(scrollController.offset == 0.0
|| scrollController.position.extentBefore == 0.0
|| scrollController.position.extentAfter == 0.0){
scrollPhysics = NeverScrollableScrollPhysics();
Future.delayed(Duration(seconds: 1), (){
scrollPhysics = ClampingScrollPhysics();
setState((){});
});
setState((){});;
}
}
Expanded(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: requestList.length,
itemBuilder: (BuildContext context, int index) {
int que = index;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.only(
left: 20,
top: 10,
bottom: 10,
right: 20),
child: Text(
'${que++} . ${requestList[index].question}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: HexColor(HexColor.black),
fontFamily: 'montserrat_regular',
decoration: TextDecoration.none,
),
)),
ListView.builder(
itemCount: requestList[index].questionOptions!.length,
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int subindex) {
return Row(
children: <Widget>[
Radio(
value: 1,
groupValue: radio_value[index],
onChanged: (values) async {
setState(() {
radio_value[index] = 1;
qutionCheckModel[index].response =
"yes";
});
}),
Container(
child: Text(
requestList[index].questionOptions![subindex],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: HexColor(HexColor.black),
fontFamily: 'montserrat_regular',
decoration: TextDecoration.none,
),
),
),
],
);
}),
],
);
}),
),