关键逻辑在于使用 NotificationListener 监听到 OverscrollNotification ,将子组件不滑动的部分传递给父组件去滑动。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: SafeArea(
child: Scroll(),
),
),
);
}
}
class Scroll extends StatefulWidget {
const Scroll({super.key});
@override
State<Scroll> createState() => _ScrollState();
}
class _ScrollState extends State<Scroll> {
final _controller = ScrollController();
@override
Widget build(BuildContext context) {
return Expanded(
child: NotificationListener(
onNotification: (notification) {
if (notification is OverscrollNotification) {
final d = notification.dragDetails?.delta.dy ?? 0;
final offset = _controller.offset - d;
_controller.jumpTo(offset);
}
return true;
},
child: SingleChildScrollView(
controller: _controller,
child: Column(
children: [
Container(
height: 200,
color: Colors.redAccent,
),
SizedBox(
height: 300,
child: ListView.separated(
shrinkWrap: true,
padding: const EdgeInsets.only(bottom: 50),
itemBuilder: (context, index) {
return SizedBox(
width: 360,
height: 50,
child: Text('index $index'),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 20,
),
),
Container(
height: 200,
color: Colors.yellowAccent,
),
SizedBox(
height: 300,
child: ListView.separated(
shrinkWrap: true,
padding: const EdgeInsets.only(bottom: 50),
itemBuilder: (context, index) {
return SizedBox(
width: 360,
height: 50,
child: Text('index $index'),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 20,
),
),
Container(
height: 200,
color: Colors.blueAccent,
),
],
),
),
),
);
}
}