Reputation: 57
I have already gone through this post
for nested scrolling but it is not the correct way according to me as explained in this video from the official flutter channel
I want to achieve the below layout
The list header like Claim requested credentials,Claim received credentials,Pending Requests etc are dynamic and will be coming from backend. Also each item in those list header like Module 1: Designing Financial Services are also dynamic
So I need list within a list
I am using a CustomScroll but I am not able to achieve the inner list view
I am looking for a lazy list option and not just mapping the inner list over a column or a list as the inner list might contain 100 items
Here is what I have achieved
Here is the sample code
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
HeaderGradient(),
Positioned(
top: 110,
left: 0,
right: 0,
bottom: 0,
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: const BoxDecoration(
color: grayColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: ManageCredentialHeader(),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return ManageCredentialCard();
}, childCount: 10))
],
),
),
)
],
),
);
}
}
and
class ManageCredentialCard extends StatelessWidget {
const ManageCredentialCard({super.key});
@override
Widget build(BuildContext context) {
return Card(
color: Theme.of(context).colorScheme.background,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Column(
children: [
const ManageCredentialCardHeader(),
const ManageCredentialCardItem()
],
),
),
);
}
}
ManageCredentialCardItem
is the inner list
As soon as I wrap ManageCredentialCardItem
inside a ListView.builder
I get error saying
RenderFlex children have non-zero flex but incoming height constraints are
unbounded.
When a column is in a parent that does not provide a finite height constraint,
for example if it is
in a vertical scrollable, it will try to shrink-wrap its children along the
vertical axis. Setting a
flex on a child (e.g. using Expanded) indicates that the child is to expand to
fill the remaining
space in the vertical direction.
Check the sample repo to check what I have tried and full source code
Upvotes: 3
Views: 2746
Reputation: 63769
I was referring generating everything on sliver like
child: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: ManageCredentialHeader(),
),
for (int i = 0; i < 10; i++)
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
childCount: 10 + 1, //extend by 1 for header
(context, index) {
return index == 0
? const ManageCredentialCardHeader()
: const ManageCredentialCardItem();
}),
),
)
],
),
Also you can create custom-sliver for children.
Upvotes: 2
Reputation: 4836
I'm not really sure about what effect you want to achieve, but :
If your goal is to display the full list of items in your ManageCredentialCard
like this:
you just need to update the ManageCredentialCard
widget with the following
class ManageCredentialCard extends StatelessWidget {
const ManageCredentialCard({super.key});
@override
Widget build(BuildContext context) {
return Card(
color: Theme.of(context).colorScheme.background,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Column(
children: [
const ManageCredentialCardHeader(),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const ManageCredentialCardItem();
},
itemCount: 20,
)
// const ManageCredentialCardItem()
],
),
),
);
}
}
BUT
If your goal is to limit the size of your Cards
, and be able to scroll the Items list like this
you will have to define a height limit to your Cards with a SizeBox
.
class ManageCredentialCard extends StatelessWidget {
const ManageCredentialCard({super.key});
@override
Widget build(BuildContext context) {
return Card(
color: Theme.of(context).colorScheme.background,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Column(
children: [
const ManageCredentialCardHeader(),
SizedBox(
height: 150,
child: ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemBuilder: (context, index) {
return const ManageCredentialCardItem();
},
itemCount: 10,
),
)
// const ManageCredentialCardItem()
],
),
),
);
}
}
The only thing you'll have to do then would be to scroll the main Listview
when reaching the end of one of the inner-lists.
To do so, you can use the NotificationListener
widget as explained in this post :
Flutter : ListView : Scroll parent ListView when child ListView reach bottom - ClampingScrollPhysics not working in sized container
Upvotes: 0
Reputation: 25080
As @Yeasin Sheikh suggested, you dont need to use Listview.builder
inside ManageCredentialCardItem
because the parent of ManageCredentialCardItem
is handling the scroll i.e
SliverList( // 👈 This will handle scroll
delegate: SliverChildBuilderDelegate((context, index) {
return ManageCredentialCard(); //👈 So you can use column instead
},childCount: 10))
If you have useCase where you have to use ListView.builder
for fetching the results from remote source, you can use shrinkWrap: true
prop inside ListView.builder
Upvotes: 0
Reputation: 61
To solve the ‘ListView.builder’ problem, I suggest to wrap it into an ’Expanded’ and set the ’shrinkWrap’ property of the ’ListView’ to true.
As for the list inside a list problem I’m not sure I understand correctly, but setting the ’primary’ property of the inner List to false should make it so it follows the scroll of the general list and avoids scrolling internally.
It might be needed to also set the ’shrinkWrap’ to true since it has no defined height, making it not lazy, but I’d try also wrapping it with ’Expanded’ as it might have the same result keeping it lazy
Upvotes: 0