简体   繁体   English

Flutter - 如何在小部件滚动到屏幕时创建小部件

[英]Flutter - How to make a widget be created when it's scrolled onto the screen

I created a custom widget that adds a footer as last item to a received scrollable widget.我创建了一个自定义小部件,将页脚作为最后一项添加到收到的可滚动小部件中。 Everything works fine, but I want to change the time the footer is being created.一切正常,但我想更改创建页脚的时间。

Like ListView.builder creates items as they're scrolled onto the screen, I want that happen with the footer too.就像ListView.builder在它们滚动到屏幕上时创建项目一样,我也希望在页脚中发生这种情况。 If this custom widget receives a ListView.builder or GridView.builder , their items are being created fine as they're scrolled onto the screen, but the footer is created the first time even if it's not on the screen.如果此自定义小部件收到ListView.builderGridView.builder ,则它们的项目在滚动到屏幕上时会被很好地创建,但即使页脚不在屏幕上也是第一次创建页脚。

Here is the custom widget, where the received widget is widget.child ( ScrollView ) and the footer is widget.footer ( Widget ).这是自定义小部件,其中接收到的小部件是widget.child ( ScrollView ),页脚是widget.footer ( Widget )。

@override
Widget build(BuildContext context) {
  return Scrollable(
    controller: widget.child.controller,
    axisDirection: widget.child.getDirection(context),
    viewportBuilder: (context, offset) {
      return ShrinkWrappingViewport(
        axisDirection: widget.child.getDirection(context),
        offset: offset,
        slivers: widget.child.buildSlivers(context)
          ..add(
              SliverList(
                  delegate: SliverChildBuilderDelegate((context, index) {
            print('footer');
            return widget.footer;
          }, childCount: 1))),
      );
    },
  );
}

This is how I'm using it:这就是我使用它的方式:

ScrollableWithFooter(
  child: ListView.builder(
    itemCount: 50,
    itemBuilder: (context, index) {
      print(index);
      return SizedBox(height: 400, child: Text('Item $index'));
    },
  ),
  footer: Center(child: Text('Footer')),
)

With a list of 50, I'm seeing the first items on the screen and this is the output of the prints:有 50 个列表,我看到屏幕上的第一个项目,这是打印的 output:

I/flutter (28472): 0
I/flutter (28472): 1
I/flutter (28472): 2
I/flutter (28472): footer

And when I start scrolling, the other items start printing their indexes as they're created:当我开始滚动时,其他项目在创建时开始打印它们的索引:

I/flutter (28472): 2
I/flutter (28472): footer
I/flutter (28472): 3
I/flutter (28472): 4
I/flutter (28472): 5

This is correct for the items but not for the footer.这适用于项目,但不适用于页脚。 I want the footer to be created when I reached the end of the list, like the other items.我希望在到达列表末尾时创建页脚,就像其他项目一样。 How can achieve that?怎样才能做到这一点?

Note that on the screen everything works fine, the footer appears at the end of the list.请注意,在屏幕上一切正常,页脚出现在列表的末尾。 It's only its creation that happens before it should.只是它的创造发生在它应该发生之前。


This is something I tried, but it doesn't work:这是我尝试过的,但它不起作用:

@override
Widget build(BuildContext context) {
  return Scrollable(
    controller: widget.child.controller,
    axisDirection: widget.child.getDirection(context),
    viewportBuilder: (context, offset) {
      List<Widget> slivers = widget.child.buildSlivers(context);
      return ShrinkWrappingViewport(
        axisDirection: widget.child.getDirection(context),
        offset: offset,
        slivers: [
          SliverList(
              delegate: SliverChildBuilderDelegate((context, index) {
            if (index < slivers.length) {
              return slivers[index]; // <- Here seems to be the problem
            }
            print('footer');
            return widget.footer;
          }, childCount: slivers.length + 1))
        ],
      );
    },
  );
}

I get this error:我收到此错误:

The following assertion was thrown building NotificationListener<KeepAliveNotification>:
I/flutter (28472): A RenderRepaintBoundary expected a child of type RenderBox but received a child of type
I/flutter (28472): RenderSliverPadding.

you can add a listener to the controller of the listview, it will listen to the scrolling and when you hit the bottom you shall active some flag called footer,, and then show the footer您可以向列表视图的 controller 添加一个侦听器,它将侦听滚动,当您到达底部时,您将激活一些称为页脚的标志,然后显示页脚

I found a way to do this.我找到了一种方法来做到这一点。 I was doing it well, the thing is for some reason the SliverChildBuilderDelegate always creates the first 2 elements even if they're not scrolled onto the screen.我做得很好,问题是由于某种原因SliverChildBuilderDelegate总是创建前 2 个元素,即使它们没有滚动到屏幕上。 So I had to create 2 dummy invisible footers and then the real footer, this way the real footer will be created when is scrolled onto the screen:所以我必须创建 2 个虚拟的不可见页脚,然后创建真正的页脚,这样当滚动到屏幕上时,将创建真正的页脚:

@override
Widget build(BuildContext context) {
return Scrollable(
  controller: widget.child.controller,
  axisDirection: widget.child.getDirection(context),
  viewportBuilder: (context, offset) {
    return ShrinkWrappingViewport(
      axisDirection: widget.child.getDirection(context),
      offset: offset,
      slivers: widget.child.buildSlivers(context)
        ..add(SliverList(
            delegate: SliverChildBuilderDelegate((context, index) {
          if (index < 2) {
            print('dummy footer');
            return SizedBox.shrink();
          }
          print('footer');
          return widget.footer;
        }, childCount: 3))),
    );
  },
);

And this would be the final solution without the prints:这将是没有打印的最终解决方案:

@override
Widget build(BuildContext context) {
  return Scrollable(
    controller: widget.child.controller,
    axisDirection: widget.child.getDirection(context),
    viewportBuilder: (context, offset) {
      return ShrinkWrappingViewport(
        axisDirection: widget.child.getDirection(context),
        offset: offset,
        slivers: widget.child.buildSlivers(context)
          ..add(SliverList(
              delegate: SliverChildBuilderDelegate(
                  (_, index) => index < 2 ? SizedBox.shrink() : widget.footer,
                  childCount: 3))),
      );
    },
  );
}

Now the custom widget adds a footer at the bottom of any scroll view efficiently, being created both the items of the scroll view and the footer only when they're scrolled onto the screen.现在,自定义小部件在任何滚动视图的底部有效地添加了页脚,仅当滚动视图的项目和页脚滚动到屏幕上时才会创建它们。

If someone finds a better way to do this let me know.如果有人找到更好的方法来做到这一点,请告诉我。 For now, I'm okay with this solution.目前,我对这个解决方案没有意见。

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

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