flutter - Flutter:ListView:当子 ListView 到达底部时滚动父 ListView - ClampingScrollPhysics 在大小容器中不起作用
问题描述
我正在使用 Flutter 版本 1.12.13+hotfix。
我正在寻找一种能够在 ListView 内滚动并在到达底部时自动将滚动引导到父 ListView 的解决方案。
实现这一目标的第一个解决方案是使用“physics: ClampingScrollPhysics()”和“shrinkWrap: true”。所以我将此解决方案应用于除第一个(红色)之外的所有子 Listview,因为我需要将它包装在一个大小合适的 Container() 中。
问题来自第一个...... ClampingScrollPhysics() 不适用于大小的 Container() !
因此,当我滚动红色 Listview 并到达其底部时,滚动停止...我需要将手指放在此 ListView 之外才能再次滚动。
@override
Widget build(BuildContext context) {
super.build(context);
print("build MySongs");
return ListView(
children: <Widget>[
Container(
height: 170,
margin: EdgeInsets.all(16),
child: ListView(
children: <Widget>[
Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
],
),
),
Container(
margin: EdgeInsets.all(16),
child: ListView(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
],
),
),
Container(
margin: EdgeInsets.all(16),
child: ListView(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
children: <Widget>[
Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
],
),
),
Container(
margin: EdgeInsets.all(16),
child: ListView(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
],
),
),
],
);
}
也许需要在 Flutter github 问题上发布这个问题:/
解决方案
感谢 Hamed Hamedi 解决方案 :) !我认为,我基于 NotificationListener 提出了一个更好的解决方案!(感谢他,我发现了这个功能)。
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
color: Colors.yellow,
child: ListView.builder(
controller: controller,
itemBuilder: (c, i) =>
i == 10
? Container(
height: 150,
color: Colors.red,
child: NotificationListener<OverscrollNotification>(
onNotification: (OverscrollNotification value) {
if (value.overscroll < 0 && controller.offset + value.overscroll <= 0) {
if (controller.offset != 0) controller.jumpTo(0);
return true;
}
if (controller.offset + value.overscroll >= controller.position.maxScrollExtent) {
if (controller.offset != controller.position.maxScrollExtent) controller.jumpTo(controller.position.maxScrollExtent);
return true;
}
controller.jumpTo(controller.offset + value.overscroll);
return true;
},
child: ListView.builder(
itemBuilder: (c, ii) => Text('-->' + ii.toString()),
itemCount: 20,
),
),
)
: Text(i.toString()),
itemCount: 45,
),
);
}
包裹在 StatelessWidget 中的解决方案:
import 'package:flutter/material.dart';
class ScrollParent extends StatelessWidget {
final ScrollController controller;
final Widget child;
ScrollParent({this.controller, this.child});
@override
Widget build(BuildContext context) {
return NotificationListener<OverscrollNotification>(
onNotification: (OverscrollNotification value) {
if (value.overscroll < 0 && controller.offset + value.overscroll <= 0) {
if (controller.offset != 0) controller.jumpTo(0);
return true;
}
if (controller.offset + value.overscroll >= controller.position.maxScrollExtent) {
if (controller.offset != controller.position.maxScrollExtent) controller.jumpTo(controller.position.maxScrollExtent);
return true;
}
controller.jumpTo(controller.offset + value.overscroll);
return true;
},
child: child,
);
}
}
更进一步,看看 NotificationListener 的其他实现,这对分页很有用:)。你也可以试试这个:
NotificationListener<ScrollStartNotification>(
onNotification: (ScrollStartNotification value) {
final ScrollMetrics metrics = value.metrics;
if (!metrics.atEdge || metrics.pixels != 0) return true;
print("Your callback here");
return true;
},
child: child,
)
或这个 :
NotificationListener<ScrollEndNotification>(
onNotification: (ScrollEndNotification value) {
final ScrollMetrics metrics = value.metrics;
if (!metrics.atEdge || metrics.pixels == 0) return true;
print("Your callback here");
return true;
},
child: child,
)
推荐阅读
- python - 尝试解释 XGBoost 分类器的权重时出现 TypeError
- java - java - 如何接收通过Node-red发送到Java中的Reactor UdpClient / UdpServer的udp数据包?
- c# - MongoDB不会让我保存对象可能的循环引用
- npm - npm 详细堆栈错误:无法验证,需要:基本领域 =“https://npm.fontawesome.com/”,服务 =“npm.fontawesome.com”
- javascript - SharePoint Online API - 检测 NoScript (DenyAddAndCustomizePages) 状态?
- r - pivot_wider 具有复杂名称的数据框 R
- r - MATLAB中的任何内置函数都可以像R中的`ave`一样工作?
- sql - 在 UPSERT 的 UPDATE 部分,为多列计算一次表达式
- php - 执行 yii migrate 时如何修复错误“异常”?
- azure - 如何使用 @WebMvcTest、MockMvc 和 OAuth 安全性测试控制器