简体   繁体   English

如何在 Flutter 实现 Nested ListView.builder?

[英]How to implemented Nested ListView.builder in Flutter?

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对于嵌套滚动,但根据官方 flutter 频道的视频中的解释,不是正确的方法

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.列表 header,如 Claim requested credentials、Claim received credentials、Pending Requests 等是动态的,将来自后端。 Also each item in those list header like Module 1: Designing Financial Services are also dynamic此外,列表 header 中的每个项目,如模块 1:设计金融服务,也是动态的

So I need list within a list所以我需要列表中的列表

I am using a CustomScroll but I am not able to achieve the inner list view我正在使用 CustomScroll 但我无法实现内部列表视图

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我正在寻找一个惰性列表选项,而不仅仅是将内部列表映射到列或列表上,因为内部列表可能包含 100 个项目

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 ManageCredentialCardItem是内部列表

As soon as I wrap ManageCredentialCardItem inside a ListView.builder I get error saying一旦我将ManageCredentialCardItem包装在ListView.builder ,我就会收到错误提示

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检查示例 repo以检查我尝试过的内容和完整的源代码

To solve the 'ListView.builder' problem, I suggest to wrap it into an 'Expanded' and set the 'shrinkWrap' property of the 'ListView' to true.要解决“ListView.builder”问题,我建议将其包装成“Expanded”并将“ListView”的“shrinkWrap”属性设置为 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.至于列表问题中的列表,我不确定我是否理解正确,但是将内部列表的“主要”属性设置为 false 应该可以使它跟随一般列表的滚动并避免在内部滚动。

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可能还需要将 'shrinkWrap' 设置为 true,因为它没有定义高度,使其不懒惰,但我会尝试用 'Expanded' 包装它,因为它可能有相同的结果保持它懒惰

As @Yeasin Sheikh suggested, you dont need to use Listview.builder inside ManageCredentialCardItem because the parent of ManageCredentialCardItem is handling the scroll ie正如@Yeasin Sheikh 所建议的,您不需要在ManageCredentialCardItem中使用Listview.builder ,因为ManageCredentialCardItem的父级正在处理滚动,即

 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如果您有必须使用ListView.builder从远程源获取结果的用例,则可以在ListView.builder中使用shrinkWrap: true prop

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:如果您的目标是像这样在您的ManageCredentialCard中显示完整的项目列表:

在此处输入图像描述

you just need to update the ManageCredentialCard widget with the following您只需要使用以下内容更新ManageCredentialCard小部件

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如果您的目标是限制Cards的大小,并且能够像这样滚动 Items 列表

在此处输入图像描述

you will have to define a height limit to your Cards with a SizeBox .您必须使用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.您唯一需要做的就是在到达其中一个内部列表的Listview时滚动主列表视图。
To do so, you can use the NotificationListener widget as explained in this post:为此,您可以使用NotificationListener小部件,如本文所述:
Flutter: ListView: Scroll parent ListView when child ListView reach bottom - ClampingScrollPhysics not working in sized container Flutter:ListView:当子 ListView 到达底部时滚动父 ListView - ClampingScrollPhysics 在大小容器中不起作用

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.您还可以为儿童创建自定义条子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM