Flutter: Help building a scrollable ListView - flutter

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

Related

How can i make multiple text so that it can show 3 data in a block in flutter?

I want to show three data block of column, that is include date, title, and content. How can i do it? I only show 1 data that's title main.dart
Here's my code
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: <Widget>[
Card(child: ListTile(title: Text('One-line ListTile'))),
Card(
child: ListTile(
title: Text(listBlog[index].title),
subtitle: Text(listBlog[index].content),
trailing: Text(listBlog[index].date),
),
),
],
)
// ListView.separated(
// itemBuilder: (context, index) {
// return ListTile(
// title: Text(listBlog[index].title),
// trailing: Text(listBlog[index].date),
// subtitle: Text(listBlog[index].date),
// );
// },
// separatorBuilder: (context, index) {
// return Divider();
// },
// itemCount: listBlog.length),
);
}
}
You can use Column widget. Three Text will be the child of the Column.
Column(
children: const <Widget>[
Text(...),
Text(...),
Text(...)
])
Code looked like this:
ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1, color: Colors.grey),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: listBlog.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
listBlog[index].title,
), Text(
listBlog[index].content,
), Text(
listBlog[index].date,
)
]);
});

ListView.builder() builds all items in an ExpansionTile

In a list of expansion tile widgets, I'm trying to build a list (200+ items) when any expansion tile is opened. When i open the expansion tile it builds all the 200 items at once, giving a jank. I'm using Listview.builder so I'm not expecting this behavior. Here's a code snippet.
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 100,
itemBuilder: (context, i) {
final _expansionTileKey = GlobalKey();
return ExpansionTile(
initiallyExpanded: false,
textColor: Colors.black,
key: _expansionTileKey,
onExpansionChanged: (value) =>
widget.onExpansionChanged(_expansionTileKey),
trailing: Icon(
Icons.keyboard_arrow_down,
),
subtitle: Text(
"$i - $i",
),
title: Text(
'$i',
),
children: <Widget>[
StreamBuilder<List<T>>(
stream: _bloc.stream,
builder: (context, snapshot) {
return ListView.separated(
shrinkWrap: true,
itemCount: _bloc.length,
itemBuilder: (_, index) {
return Container(
color: Colors.white,
child: Text("$index"),
);
},
separatorBuilder: (_, i) => Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: const Divider(
height: 1,
),
),
);
},
)
],
);
},
),

Put a divider after a text in -- nested ListView.builder of Flutter

My aim is to put a Divider line after the text of the inner ListView.builder.
What's the way to do that?
List<String> list1 = ["pppp", "qqqq", "rrrr"];
List<String> list2 = ["aaaa", "bbbb", "cccc"];
#override
Widget build(BuildContext ctxt) {
return new Scaffold(
body: new Column(
children: <Widget>[
new Expanded(
child: new ListView.builder(
itemCount: list1.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: list2.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new Text(
list2[Index],
style: TextStyle(color: Colors.green, fontSize: 25),
);
}
);
}),
),
],
),
);
}
You can add a divider by placing SizedBox as shown in the code below:
List<String> list1 = ["pppp", "qqqq", "rrrr"];
List<String> list2 = ["aaaa", "bbbb", "cccc"];
#override
Widget build(BuildContext ctxt) {
return new Scaffold(
body: new Column(
children: <Widget>[
new Expanded(
child: Column(
children: [
new ListView.builder(
itemCount: list1.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: list2.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
list2[Index],
style: TextStyle(color: Colors.green, fontSize: 25),
);
});
}),
Divider(
height: 3,
thickness: 1,
indent: 10, // Space at the start.
endIndent: 10, // Space at the end.
),
],
),
),
],
),
);
}
Please change the height of the SizedBox as required.
Let's try with ListView.separated
List<String> list1 = ["pppp", "qqqq", "rrrr"];
List<String> list2 = ["aaaa", "bbbb", "cccc"];
#override
Widget build(BuildContext ctxt) {
return new Scaffold(
body: new Column(
children: <Widget>[
new Expanded(
child: new ListView.separated(
itemCount: list1.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: list2.length,
itemBuilder: (BuildContext ctxt, int Index) {
return new Text(
list2[Index],
style: TextStyle(color: Colors.green, fontSize: 25),
);
},
);
},
separatorBuilder: (context, build)=>Divider(
thickness: 1,
color: Color(0xff002540).withOpacity(.1),
),
),
),
],
),
);
}
Output:
You can use ListView.separated
More on that https://medium.com/flutter-community/flutter-adding-separator-in-listview-c501fe568c76#:~:text=separated.-,ListView.,indices%20%E2%89%A5%200%20and%3C%20itemCount%20.

How to use Expansion Tile with ListView inside Column in Flutter

I am trying to create a custom drawer.
I want to make DrawerHeader fixed. However, I want ExpansionTile and ListView scrollable.
https://imgur.com/a/lWeDWOO ,
https://imgur.com/a/tR68ECK
class _NavigationDrawerState extends State<NavigationDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
DrawerHeader(
child: Column(....),
ExpansionTile(
title: Text('Roles'),
children: [
ListView.builder(
itemBuilder: _buildRolesList,
itemCount: roles.length,
shrinkWrap: true,
)
],
),
ListView.builder(
shrinkWrap: true,
itemBuilder: _buildList,
itemCount: myList.length,
),
],
),
);
}
Widget _buildList(BuildContext context, int index) {
return ListTile(
leading: Icon(icons[myList[index].toLowerCase()]),
title: Text(myList[index]),
);
}
Widget _buildRolesList(BuildContext context, int index) {
return ListTile(
dense: true,
title: Text(roles[index]),
onTap: () {},
);
}
}
Try this:
class _NavigationDrawerState extends State<NavigationDrawer> {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
ExpansionTile(
title: Text('Roles'),
children: [
SizedBox(
height: MediaQuery.of(context).size.height - 100,
child: ListView.builder(
itemBuilder: _buildRolesList,
itemCount: roles.length,
shrinkWrap: true,
),
)
],
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: _buildList,
itemCount: myList.length,
),
),
],
),
);
}
Widget _buildList(BuildContext context, int index) {
return ListTile(
leading: Icon(icons[myList[index].toLowerCase()]),
title: Text(myList[index]),
);
}
Widget _buildRolesList(BuildContext context, int index) {
return ListTile(
dense: true,
title: Text(roles[index]),
onTap: () {},
);
}

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