Flutter - 如何在滚动到屏幕上时创建小部件
Flutter - How to make a widget be created when it's scrolled onto the screen
我创建了一个自定义小部件,将页脚作为最后一项添加到接收到的可滚动小部件中。一切正常,但我想更改创建页脚的时间。
就像 ListView.builder
在滚动到屏幕上时创建项目一样,我希望页脚也能发生这种情况。如果此自定义小部件收到 ListView.builder
或 GridView.builder
,它们的项目在滚动到屏幕上时创建良好,但页脚是第一次创建,即使它不在屏幕上也是如此。
这里是自定义的widget,接收到的widget是widget.child
(ScrollView
),footer是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))),
);
},
);
}
我是这样使用它的:
ScrollableWithFooter(
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
print(index);
return SizedBox(height: 400, child: Text('Item $index'));
},
),
footer: Center(child: Text('Footer')),
)
列表中有 50 个,我在屏幕上看到了第一个项目,这是打印的输出:
I/flutter (28472): 0
I/flutter (28472): 1
I/flutter (28472): 2
I/flutter (28472): footer
当我开始滚动时,其他项目开始打印它们创建的索引:
I/flutter (28472): 2
I/flutter (28472): footer
I/flutter (28472): 3
I/flutter (28472): 4
I/flutter (28472): 5
这对项目是正确的,但对页脚不正确。我希望在到达列表末尾时创建页脚,就像其他项目一样。如何实现?
请注意,在屏幕上一切正常,页脚出现在列表的末尾。只是它的创建发生在它应该发生的时间之前。
这是我试过的方法,但它不起作用:
@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))
],
);
},
);
}
我收到这个错误:
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.
您可以向列表视图的控制器添加一个侦听器,它将侦听滚动,当您到达底部时,您将激活一些名为 footer 的标志,然后显示页脚
我找到了一种方法来做到这一点。我做得很好,事情是出于某种原因 SliverChildBuilderDelegate
总是创建前 2 个元素,即使它们没有滚动到屏幕上。所以我不得不创建 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))),
);
},
);
这将是没有指纹的最终解决方案:
@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))),
);
},
);
}
现在,自定义小部件可以在任何滚动视图的底部高效地添加页脚,只有在滚动视图的项目和页脚滚动到屏幕上时才会创建它们。
如果有人找到更好的方法,请告诉我。目前,我对这个解决方案没意见。
我创建了一个自定义小部件,将页脚作为最后一项添加到接收到的可滚动小部件中。一切正常,但我想更改创建页脚的时间。
就像 ListView.builder
在滚动到屏幕上时创建项目一样,我希望页脚也能发生这种情况。如果此自定义小部件收到 ListView.builder
或 GridView.builder
,它们的项目在滚动到屏幕上时创建良好,但页脚是第一次创建,即使它不在屏幕上也是如此。
这里是自定义的widget,接收到的widget是widget.child
(ScrollView
),footer是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))),
);
},
);
}
我是这样使用它的:
ScrollableWithFooter(
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
print(index);
return SizedBox(height: 400, child: Text('Item $index'));
},
),
footer: Center(child: Text('Footer')),
)
列表中有 50 个,我在屏幕上看到了第一个项目,这是打印的输出:
I/flutter (28472): 0
I/flutter (28472): 1
I/flutter (28472): 2
I/flutter (28472): footer
当我开始滚动时,其他项目开始打印它们创建的索引:
I/flutter (28472): 2
I/flutter (28472): footer
I/flutter (28472): 3
I/flutter (28472): 4
I/flutter (28472): 5
这对项目是正确的,但对页脚不正确。我希望在到达列表末尾时创建页脚,就像其他项目一样。如何实现?
请注意,在屏幕上一切正常,页脚出现在列表的末尾。只是它的创建发生在它应该发生的时间之前。
这是我试过的方法,但它不起作用:
@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))
],
);
},
);
}
我收到这个错误:
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.
您可以向列表视图的控制器添加一个侦听器,它将侦听滚动,当您到达底部时,您将激活一些名为 footer 的标志,然后显示页脚
我找到了一种方法来做到这一点。我做得很好,事情是出于某种原因 SliverChildBuilderDelegate
总是创建前 2 个元素,即使它们没有滚动到屏幕上。所以我不得不创建 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))),
);
},
);
这将是没有指纹的最终解决方案:
@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))),
);
},
);
}
现在,自定义小部件可以在任何滚动视图的底部高效地添加页脚,只有在滚动视图的项目和页脚滚动到屏幕上时才会创建它们。
如果有人找到更好的方法,请告诉我。目前,我对这个解决方案没意见。