I am trying find a way for the user to Scroll Parent Widget when Child Widgets have been scrolled to the top or bottom, whilst maintaining the scroll velocity / scroll momentum / scroll physics / user experience.
A good demonstration of what I'm trying to achieve (albeit without BouncingScrollPhysics): https://i.stack.imgur.com/qpfNP.jpg Taken from: Flutter: Continue scrolling in top Listview when reaching bottom of nested Listview
I appreciate lots of similar questions to this have been asked already, with answers relating to NotificationListener, which I have tried. However this method does not maintain the scroll velocity / scroll momentum / scroll physics / user experience, so leads to a poor quality user experience. Flutter: Continue scrolling in top Listview when reaching bottom of nested Listview looks to use a different method that might achieve the desired results, but I'm unable to get it to work correctly / with allowed operation conditions).
It seems odd there is not yet an answer to fully satisfies the desired functionality as it is very common on websites. It's clear by the number of questions on this topic, a full solution would be really appreciated.
Best Q&As so far:
- Flutter : ListView : Scroll parent ListView when child ListView reach bottom - ClampingScrollPhysics not working in sized container
- Is there any way to scroll parent listview when the child listview reached end in flutter?
- Flutter: Continue scrolling in top Listview when reaching bottom of nested Listview
Other similar Q&As:
I have created some basic code that can be used to test / demonstrate solutions that 'everyone' should be able to understand easily:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _textAController = ScrollController();
final ScrollController _textBController = ScrollController();
final ScrollController _pageController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
controller: _pageController,
children: [
Container(
height: 200,
color: Colors.green,
),
Container(
height: 200,
color: Colors.red,
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200),
child: SingleChildScrollView(
padding: const EdgeInsets.only(right: 15),
controller: _textAController,
physics: const ClampingScrollPhysics(),
child: Column(
children: [
const Text(
'Scrollable Child 1',
softWrap: true,
textAlign: TextAlign.center,
),
Container(
color: Colors.amber,
height: 600,
)
],
),
),
),
),
Container(
height: 10,
color: Colors.purple,
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200),
child: SingleChildScrollView(
controller: _textBController,
physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(right: 15),
child: Column(
children: [
const Text(
'Scrollable Child 2',
softWrap: true,
textAlign: TextAlign.center,
),
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (BuildContext context, index) {
return Container(
height: 12,
width: 50,
color: Colors.grey,
);
},
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 60,
color: Colors.black,
);
},
),
],
),
),
),
),
Container(
height: 100,
color: Colors.blue,
),
],
),
);
}
}