Is there a way to detect if a scroll in
PageView
(PageController
) orScrollable
widget (ScrollController
)is done manually by a user or programatically using jumpTo()
or animateTo()
on the controller objects.
Wrapping the scrollable widget in a NotificationListener
also does not give us any such callback or flag.
I found a solution around this but I find it a little hacky and would like to know if there is a better solution for it:
My Solution:
Wrap the Scrollable
widget in a GestureDetector
widget and use the onTapUp
and onTapDown
callback functions to and set a flag (isScrollManual
) to check if the scroll is manual or programatically.
Here is the code:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyPageControllers(),
),
),
);
}
}
class MyPageControllers extends StatefulWidget {
@override
_MyPageControllersState createState() => _MyPageControllersState();
}
class _MyPageControllersState extends State<MyPageControllers> {
PageController _controller1;
bool isScrollManual = false;
@override
void initState() {
super.initState();
_controller1 = PageController();
_controller1.addListener(() {
if(isScrollManual){
/// Manual Scroll
}else{
/// Programmatic scroll
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: GestureDetector(
onTapDown: (tapDownDetails){
isScrollManual = true;
setState(() {});
},
onTapUp: (tapUpDetails){
isScrollManual = false;
setState(() {});
},
child: PageView.builder(
controller: _controller1,
itemBuilder: _itemBuilder,
),
),
);
}
Widget _itemBuilder(BuildContext context, int index) =>
Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Text(
index.toString(),
style: TextStyle(color: Colors.white, fontSize: 60),
),
),
);
}
The only working solution I found was to wrap the Scrollable
widget in a GestureDetector
widget and use the onTapUp
and onTapDown
callback functions to and set a flag (isScrollManual
) to check if the scroll is manual or programatically.
Here is the code:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyPageControllers(),
),
),
);
}
}
class MyPageControllers extends StatefulWidget {
@override
_MyPageControllersState createState() => _MyPageControllersState();
}
class _MyPageControllersState extends State<MyPageControllers> {
PageController _controller1;
bool isScrollManual = false;
@override
void initState() {
super.initState();
_controller1 = PageController();
_controller1.addListener(() {
if(isScrollManual){
/// Manual Scroll
}else{
/// Programmatic scroll
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: GestureDetector(
onTapDown: (tapDownDetails){
isScrollManual = true;
setState(() {});
},
onTapUp: (tapUpDetails){
isScrollManual = false;
setState(() {});
},
child: PageView.builder(
controller: _controller1,
itemBuilder: _itemBuilder,
),
),
);
}
Widget _itemBuilder(BuildContext context, int index) =>
Container(
color: Colors.primaries[index % Colors.primaries.length],
child: Center(
child: Text(
index.toString(),
style: TextStyle(color: Colors.white, fontSize: 60),
),
),
);
}