How to put two parallel flutter lists in a column - flutter

I wanna put two parallel lists inside the row marked in the picture. I've tried different types of structures, but all give me problems.
Each element of the dynamic lists will have a picture and a Text.
Screen
I've been trying to put two sized box inside the row:
Row(children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
),
])
After the width putting the ListView
Everything I try gives me the next error:
error

Please refer to below code
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 15,
itemBuilder: (BuildContext context,
int index) {
return ListTile(
leading: Icon(
Icons.star_border,
),
title: Text(
'List $index' +
"Lorem ipsum dolor sit amet, ",
),
);
},
),
],
),
),
Flexible(
child: Padding(
padding: EdgeInsets.only(left: 15.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
ListView.builder(
physics:
NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 15,
itemBuilder: (BuildContext context,
int index) {
return Row(
children: [
Icon(
Icons.star,
),
Text("List item $index"),
],
);
},
),
],
),
),
)
],
),

Try this :
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListView.builder(
shrinkWrap:true,
builder:(context,index)=> Container(),
),
ListView.builder(
shrinkWrap:true,
builder:(context,index)=> Container(),
),
],
);

Related

Shrink list view when less items are present

I'm trying to make a widget that displays two list view (one under the groups header, the other under the alerts header) with a minimum and maximum height.
I've managed to get maximum heights working via a ConstrainedBox wrapping everything however I've been unable to get a mimnimum height working. Idearly I would like the lists to like everything to shink if there are fewer items in both lists.
For example, in the screenshot below there are only two items in one list and none in the other so I would like the overall widget to shrink down to roughly half its current size
From what I can see in the Widget Inspector, the list itself is not taking up any more space than it needs however the Column appears to be taking up all the space the parent constraint is allowing for. I've tried messing with mainAxisSize: MainAxisSize.min, howeve this doesn't appear to have had any effect.
How can I prevent this column from taking all the extra space?
return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 300, minHeight: 50),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Flexible(
flex: 1,
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(padding: EdgeInsets.all(10), child: Text("Groups")),
const Divider(),
ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (context, index) => ListTile(
...
))
],
),
),
),
Flexible(
flex: 1,
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(padding: EdgeInsets.all(10), child: Text("Alerts")),
const Divider(),
ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (context, index) => ListTile(
...
))
],
),
),
),
],
),
);
Edit after suggestions:
Try this
Remove crossAxisAlignment: CrossAxisAlignment.stretch from the row
Add mainAxisSize: MainAxisSize.min to the columns
Edit (in response to the comment):
To make the lists same size. Not sure if there is a straightforward way.
One hacky way I can think of is by setting the itemCount of both lists equal to the length of the list with most items. And in itemBuilder, return an empty ListTile when the index is out of available items to show. Example -
import 'dart:math';
const groupsCount = 2;
const alertsCount = 4;
final biggestCount = max(groupsCount, alertsCount);
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Padding(padding: EdgeInsets.all(10), child: Text("Groups")),
const Divider(),
ListView.builder(
shrinkWrap: true,
itemCount: biggestCount,
itemBuilder: (_, index) {
if (index < groupsCount) {
return ListTile(title: Text('Group $index'));
} else {
return const ListTile();
}
},
)
],
),
),
),
Expanded(
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Padding(padding: EdgeInsets.all(10), child: Text("Alerts")),
const Divider(),
ListView.builder(
shrinkWrap: true,
itemCount: biggestCount,
itemBuilder: (_, index) {
if (index < alertsCount) {
return ListTile(title: Text('Alert $index'));
} else {
return const ListTile();
}
},
)
],
),
),
),
],
);

SliverPersistent in Row of CustomScrollView

Image
Hey guys, I want to achieve the persistent header for red area as in image. I achieved this for purple using SliverPersistentHeader but I have no idea for red area. Here's the code for my problem...
CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: DashboardSliderList(),
),
const SliverToBoxAdapter(
child: kDividerV,
),
const CategorySliverHeader(), //Sliver Persistent Header
const SliverToBoxAdapter(
child: kDividerV,
),
SliverFillRemaining(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Filter List'), // I want to get persistent this
],
),
),
Expanded(
flex: 3,
child: GridView.builder(
itemCount: 16,
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 300,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemBuilder: (context, index) {
return DashboardProductCards(
onTap: () {},
image: ImageString.dbGridviewImage,
title: 'Sweety Home',
amount: '1000000 Ks',
hoverTitle: 'L-72 W-32 H 36in ',
);
}),
),
],
),
),
],
)

Flutter how to dynamically get the height of my page and my Listview.Builder?

I'm wondering how to get the height of my page dynamically with a Listview.Builder()` inside. This is my page tree:
This is my News.dart
return SafeArea(
child: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
child: Container(
height: MediaQuery.of(context).size.height * 5,
margin: EdgeInsets.all(25),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
...
Later on we have the Listview.Builder()
Expanded(child: Consumer<Model>(
builder: (context, myModel, child) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: list.length,
itemBuilder: (ctx, index) =>
ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {
setState(() {
},
child: Item(),
),
),
);
})),
Now below my SingleChildScrollView() I have a Container with height of MediaQuery.of(context).size.height * 5, I want to have my complete Screen height dynamic. If I remove the height value, I'm getting the render layout error because there is no parent defining a size. This Page here is Part of a TabbarNavigation and this is the content.
Can anybody tell me how to get the dynamic height of the ListView.Builder() ?
EDIT:
The following is my Tabbar where I define the pages inside the tabbar. One of them is my News.dart
This is the Tabbar.dart:
final List<Widget> _pages = [
NewsScreen(),
TrendScreen(),
OtherScreen(),
];
return Scaffold(
extendBodyBehindAppBar: true,
body: _pages[provider.currentIndex],
bottomNavigationBar: provider.currentIndex != 2
? Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
CustomWidget(),
BottomNavigationBar(
onTap: _selectPage,
backgroundColor: Theme.of(context).primaryColor,
unselectedItemColor: Color.fromRGBO(130, 130, 130, 1),
selectedItemColor: Color.fromRGBO(236, 37, 105, 1),
selectedFontSize: 10,
iconSize: 22,
currentIndex: provider.currentIndex,
type: BottomNavigationBarType.fixed,
selectedLabelStyle: TextStyle(fontSize: 12),
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.home),
title: Text(
'home',
style: TextStyle(
fontSize: 10,
),
),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.star),
title: Text(
'News',
style: TextStyle(
fontSize: 10,
),
),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.play_arrow),
title: Text('other',
style: TextStyle(
fontSize: 10,
)),
),
],
),
])
: null,
);
}
Credits to #pskink !!
Working with CustomScrollView() instead of SingleChildScrollView(), SliverToBoxAdapter() and SliverList() made everything work like charm!
return SafeArea(
child: CustomScrollView(
//scrollDirection: Axis.vertical,
physics: BouncingScrollPhysics(),
slivers: <Widget>[
// Place sliver widgets here
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(25, 30, 25, 20),
child: SizedBox(
height: 299,
child: Column(children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
...
And a list example:
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, index) => ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {}),
childCount: rrr.length,
)),
You can Use the "Flex" property of the already used Expanded() widget.
first remove the Container at the Top.
return SafeArea(
child: Scrollbar(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
dragStartBehavior: DragStartBehavior.start,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
...
and then,
Column(
children: <Widget>[
Expanded(
flex : 1,
child: Consumer<Model>(
builder: (context, myModel, child) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: list.length,
itemBuilder: (ctx, index) =>
ChangeNotifierProvider.value(
value: list[index],
child: GestureDetector(
onTap: () {
setState(() {
},
child: Item(),
),
),
;
})),
]),
API Docs : https://api.flutter.dev/flutter/widgets/Expanded-class.html
Flutter Widget of the Week : https://www.youtube.com/watch?v=_rnZaagadyo

Flutter_Swiper text over image

I have started playing around with Flutter Swiper (https://pub.dev/packages/flutter_swiper) and so far it is very powerful!
The only thing I can't make it do is overlay the text on the image. Here is my code with the text displayed below the image:
new Swiper(
outer: false,
itemBuilder: (BuildContext context, int index) {
return new Column(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Container(
child: new Container(
child: new Image.asset(dateIdeas[index]),
),
),
new Text(
"test",
textAlign: TextAlign.start,
),
],
),
],
);
},
itemCount: dateIdeas.length,
layout: SwiperLayout.DEFAULT,
itemHeight: 800,
itemWidth: 400,
),
This displays the word "Test" below the image, and the text moves as the image is swiped. However I cannot make the text overlay on the image. I have tried adding padding and increasing the "bottom" value to shift the text up but it does not move. Annoyingly it does shift the text left, right and down when asked.
Does anyone have any idea on how to do this?
Use a Stack
Swiper(
outer: false,
itemBuilder: (BuildContext context, int index) {
return new Column(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Stack(
children: <Widget>[
new Container(
child: new Image.asset(dateIdeas[index]),
),
new Text(
"test",
textAlign: TextAlign.start,
),
],
)
],
),
],
);
},
// itemCount: dateIdeas.length,
// layout: SwiperLayout.DEFAULT,
itemHeight: 800,
itemWidth: 400,
);

ListView inside a Row with dynamic width

I want to create a ListView and a Button to add items to the ListView.
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Conversation conversation = teamMembers[index];
return SizedBox(
width: 42,
height: 42,
child: Avatar(
name: member.name,
profileUrl: member.profileUrl,
radius: 38,
),
);
},
itemCount: teamMembers.length,
),
),
InkWell(
onTap: () {
_showSheet();
},
child: Container(
width: 42,
height: 42,
decoration: new BoxDecoration(
color: Color(0xfff2f2f2),
borderRadius: BorderRadius.circular(28)),
child: Icon(Icons.add),
),
),
],
)
I'm getting the results as below for lesser number of items and more number of items. How can I make the + button closer to the ListView even if the list length is less.
List<Widget> _buttons = [];
Wrap(
spacing: 12.0, // horiz
runSpacing: 12.0, // vert
crossAxisAlignment: WrapCrossAlignment.start,
alignment: WrapAlignment.start,
children: _buttons,
),
The solution to this issue is replacing the Expanded widget with Flexible widget.
Expanded actually is just a shorthand for Flexible. Flexible takes only the needed space, and Expanded takes all available space, respecting the flex factor.
Flexible with fit: FlexFit.loose which is the default one solves the problem. If the fit is FlexFit.loose, the child can be at most as large as the available space (but is allowed to be smaller)
So,
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Conversation conversation = teamMembers[index];
return SizedBox(
width: 42,
height: 42,
child: Avatar(
name: member.name,
profileUrl: member.profileUrl,
radius: 38,
),
);
},
itemCount: teamMembers.length,
),
),
InkWell(
onTap: () {
_showSheet();
},
child: Container(
width: 42,
height: 42,
decoration: new BoxDecoration(
color: Color(0xfff2f2f2),
borderRadius: BorderRadius.circular(28)),
child: Icon(Icons.add),
),
),
],
)
is the solution.