Eng*_*Eng 8 flutter flutter-layout
我正在使用 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)),
],
),
),
],
);
}
Run Code Online (Sandbox Code Playgroud)
也许需要在 Flutter github 问题上发布这个问题:/
Eng*_*Eng 15
感谢 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,
),
);
}
Run Code Online (Sandbox Code Playgroud)
解决方案包含在 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,
);
}
}
Run Code Online (Sandbox Code Playgroud)
更进一步,看看 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,
)
Run Code Online (Sandbox Code Playgroud)
或这个 :
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,
)
Run Code Online (Sandbox Code Playgroud)
一个棘手的方法可能是使用NotificationListener. 将过度滚动通知侦听器放在您的子滚动小部件上,然后在过度滚动的情况下忽略指针。要让子部件再次向相反方向滚动,您必须在短时间内设置 ignoring false。详细的代码示例:
class _MyHomePageState extends State<MyHomePage> {
var _scrollParent = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.yellow,
child: ListView.builder(
itemBuilder: (c, i) => i == 10
? Container(
height: 150,
color: Colors.red,
child: IgnorePointer(
ignoring: _scrollParent,
child: NotificationListener<OverscrollNotification>(
onNotification: (_) {
setState(() {
_scrollParent = true;
});
Timer(Duration(seconds: 1), () {
setState(() {
_scrollParent = false;
});
});
return false;
},
child: ListView.builder(
itemBuilder: (c, ii) => Text('-->' + ii.toString()),
itemCount: 100,
),
),
),
)
: Text(i.toString()),
itemCount: 100,
),
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
会存在一些缺陷,例如用户需要双滚动才能激活父滚动事件(第一个将忽略指针),或者使用计时器禁用忽略导致快速滚动操作中的不当行为。但是对于其他解决方案的实施简单性将是巨大的。
| 归档时间: |
|
| 查看次数: |
4415 次 |
| 最近记录: |