Several Listviews with same scroll - flutter

How can I have in Flutter more than one Listview but using same scroll for both?
My idea is having something like this:
ListTile
ListTile
ListTile
...
Some content
ListTile
ListTile
ListTile
...
I could move that content inside the Listview itself but it gets a bit messy and I'd prefer having different widgets

You have some options , one is with SingleChildScrollView, Column and removing the scroll of your Lists, or also you can do it with Slivers.
This is a sample using the first option:
Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (_, index) => ListTile(
title: Text("Group 1 : Item $index"),
),
itemCount: 9,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Some content"),
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (_, index) => ListTile(
title: Text("Group 2 : Item $index"),
),
itemCount: 9,
),
],
),
),
);
If you want to use Slivers, check this awesome post from Emily Fortuna; https://medium.com/flutter/slivers-demystified-6ff68ab0296f

Related

Remove whitespace between two ListView inside Column in Dialog - Flutter

I need to show two ListViews inside a dialog; I am using the showDialog function and in the "content" attribute I added a "SizedBox" without any value for the "height" attribute, and the lists are inside the Column object. Here is the code:
showDialog(
context: context,
builder: (context) => AlertDialog(
content: SizedBox(
width: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('Text1'),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: listOne.length,
itemBuilder: (context, index) {
return Text(listOne.elementAt(index).name);
},
),
),
Text('Text 2'),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: listTwo.length,
itemBuilder: (context, index) {
return Text(listTwo.elementAt(index).name);
},
),
),
],
),
),
),
);
I have already checked that the item count for both lists is correct.
Here is the result:
I want to remove the big whitespace between the two lists if it possibile.
Hope someone can help me.
Expanded: A widget that expands a child of a Row, Column, or Flex so
that the child fills the available space.
so by default it will expand fills the full height of screen.
Workaround:
change with Flexible widget:
unlike Expanded, Flexible does not require the child to fill the available space.
children: [
Text('Text1'),
Flexible(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: 3,
itemBuilder: (context, index) {
return Text('.name');
},
),
),
Text('Text 2'),
Flexible(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: 4,
itemBuilder: (context, index) {
return Text('.name');
},
),
),
],
The white space is coming for the Expanded widget trying to expand to full size extent of the screen for both lists. if you change the Expanded widget with Sizedbox and give it a height for both list it will remove the white space in between and after.
I hope this helps

Make RefreshIndicator work on whole screen (ListView)

While looking for solutions, I found some related discussions, but none of the solutions worked in my case.
I made a "RefreshableScrollFrame" widget in my app, which offers a generic frame for pages that should show a StatusBar (loading indicator, etc.) and which should provide a pull-down to refresh.
RefreshableScrollFrame
return Center(
child: Column(
children: [
SizedBox(
height: 4,
child: const MyStatusbarWidget(),
),
RefreshIndicator(
onRefresh: onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: child,
),
)
],
),
);
Child Option - ListView:
ListView.builder(
itemCount: items.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, i) => Card(
child: ListTile(
title: Text(items[i].name),
),
),
);
Child Option - Column with the ListView and static items:
Column(
children: [
ListView.builder(
itemCount: items.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, i) => Card(
child: ListTile(
title: Text(items[i].name),
),
),
),
...someStaticWidgets,
],
);
So far so good, everything works fine, except for one important detail.
The RefreshIndicator is only triggered in areas, which are covered by the child widget. If the content is small and covers just the top of the page, the gesture is detected only in that area.
If the content is just an empty ListView, I won't even be able to trigger a refresh.
I tried several suggested solutions in order to "expand" the child to the whole screen, but I always ran into exceptions, when trying to get rid of shrinkWrap, when adding Expanded(), and so on.
Any hints would be appreciated.
you have to wrap the whole body of your scaffold with refreshIndicator not a portion of it.
I found a solution that seems to work for me, using a LayoutBuilder + ConstrainedBox to wrap the contents of the SingleChildScrollView.
This way, the SingleChildScrollView will always span the whole remaining space.
return Column(
children: [
const SizedBox(
height: 4,
child: MyStatusbarWidget(),
),
Expanded(
child: LayoutBuilder(builder: (context, constraints) {
return RefreshIndicator(
onRefresh: onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: child,
),
),
),
);
}),
),
],
);

Using both horizontal and vertical listview.builder on a page in flutter

In my application, I want to show two different products on the home screen, horizontally and vertically. But I want to do this with ListView.Builder as they both come as lists. I couldn't find the right usage of this, can you help with this?
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 200.0,
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 25,
itemBuilder: (BuildContext context, int index) =>
Card(
child: Center(child: Text('Horizontal List Child')),
),
),
),
ListView.builder(
itemCount: 10,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Expanded(
child: Card(
child:
Center(child: Text('Vertical List Child'))),
);
},
)
],
),
),
I can do it without using ListView.builder but I need to use ListView.builder. The height of the vertical part should be equal to the element inside.
You must need to define the height of any scroll view. I prefer the horizontal scroll view
SingleChildScrollView(
child: Column(
children: [
Container(
height: 150,
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
...
...
...
},
),
),
ListView.builder(
itemCount: 10,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
...
...
...
},
),
],
)
)
Remove the SingleChildScrollView.
Add an Expanded as parent to the second ListView.
Remove the Expanded from the Card
Scaffold(
body: SafeArea( //in case you dont have appbar
child: CustomScrollView(
physics: const BouncingScrollPhysics(),
slivers: [
const SliverToBoxAdaptar(child:Container(child:ListView(...)))// horizontalList
const SliverList()// verticalSliverList
],
),
),
);
try thiss
Expanded makes item inside becomes full body.
just remove it and the height to make item height equals to card
return Scaffold(
appBar: AppBar(
title: Text("Sample"),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Sample 1"),
),
Container(
height: 100,
child: ListView.builder(
physics: ScrollPhysics(),
itemCount: 5,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Card(
child: Image.network("https://i.picsum.photos/id/9/250/250.jpg?hmac=tqDH5wEWHDN76mBIWEPzg1in6egMl49qZeguSaH9_VI",),
);
}
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Sample 2"),
),
ListView.builder(
physics: ScrollPhysics(),
itemCount: 5,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card(
child: Image.network("https://i.picsum.photos/id/9/250/250.jpg?hmac=tqDH5wEWHDN76mBIWEPzg1in6egMl49qZeguSaH9_VI"),
);
}
),
],
),
),
),
);

flutter: how to add a scroll bar in the right of the ListView?

I'm working with flutter. I want to add a scroll bar to the right of the ListView just similar to the net page scroll bar, but I haven't found any related property. Is this possible? The basic code is ready for your advice.
ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
// I will put some HTML code here,
],
),
There are packages available if you want custom scrollbar or you can use flutter inbuilt scrollbar widget too
draggable_scrollbar
I think better to use CupertinoScrollbar instead of Scrollbar. CupertinoScrollbar is can touch and scroll to the bottom
Ex:
CupertinoScrollbar(
isAlwaysShown: true,
controller: _scrollController,
child: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("Item: ${index + 1}"),
));
}),
),
Or You can use Scrollbar
final ScrollController _scrollController = ScrollController();
Scrollbar(
isAlwaysShown: true,
controller: _scrollController,
child: ListView.builder(
controller: _scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("Item: ${index + 1}"),
));
}),
),
You can wrap Listview with the ScrollBar widget.
ScrollBar(
isAlwaysShown: true, // optionel
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
// I will put some HTML code here,
],
),
),

How to create a combined, scrollable List in a Drawer in Flutter

I wan´t to have a combination of text-widgets and lists inside a drawer. This content should be scrollable.
Here´s my sourcecode:
return Drawer(
child: Expanded(
child: Column(
children: <Widget>[
AppBar(title: Text('Test'),),
Text('Example 1:'),
ListView.separated(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: _brands.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
....);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 5),
),
Text('Another heading')
],
),
),
);
What I want to achive:
The AppBar is fixed at the top
The other content below should be scrollable
I´ve tried different ways with Expanded, Columns etc. but I wasn´t able to get this layout up and running as expected. Thanks in advance for any input!
you can use a single column with the listview places inside an expanded widget
return Drawer(
child: Column(
children: <Widget>[
AppBar(),
Expanded(
child: ListView.separated(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: 100,
itemBuilder: (context, index) {
return Text(index.toString());
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 5),
),
),
],
),
);
yeilds
For short you can wrap your ListView with Expanded widget, it will fill all available space, but you will able to scroll it. In another case you should wrap ListView with Container and set height property.
For your example:
Drawer(
child: Column(
children: <Widget>[
AppBar(title: Text('Test'),),
Text('Example 1:'),
Expanded(
child: ListView.separated(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: List.generate(100, (index) => index).length,
itemBuilder: (BuildContext context, int index) {
return ListTile(leading: Text("$index"),);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 5),
),
),
Text('Another heading')
],
),
),