import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final GlobalKey listViewKey = GlobalKey();
@override
Widget build(BuildContext context) {
//listViewKey.currentState.
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Column(
children: [
Container(
height: 100.0,
child: ElevatedButton( //Outer button
style: ElevatedButton.styleFrom(
fixedSize: Size(
300.0,
100.0,
),
),
child: Text('top'),
onPressed: () {
//What should I do?
},
),
),
Expanded(
child: CustomListView(
key: listViewKey,
),
),
],
),
),
);
}
}
class CustomListView extends StatefulWidget {
const CustomListView({Key? key}) : super(key: key);
@override
State<CustomListView> createState() => _CustomListViewState();
}
class _CustomListViewState extends State<CustomListView> {
late final ScrollController ctrl;
double position = 0.0;
@override
void initState() {
// TODO: implement initState
super.initState();
ctrl = ScrollController()
..addListener(() {
print(ctrl.offset);
setState((){
position = ctrl.offset;
});
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Center(
child: Text(
position.toString(),
),
),
Expanded(
child: ListView(
controller: ctrl,
children: [
Container(
height: 500.0,
color: Colors.red,
),
Container(
height: 500.0,
color: Colors.green,
),
Container(
height: 500.0,
color: Colors.yellow,
),
ElevatedButton( // Inner button
onPressed: () async {
ctrl.animateTo(
0.0,
duration: Duration(
seconds: 1,
),
curve: Curves.ease,
);
},
child: Text('top'),
)
],
),
),
],
);
}
}
For example, let's say we made an app like the one above using a ready-made widget called CustomListView.
We can control scrolling by pressing a button(Inner button) inside the CustomListView. This is fine.
but what if, for example, we want to control the scrolling of a ListView inside a CustomListView when we press the Outer button?
↓For example, in the CustomListView definition, make the CustomListView receive a ScrollController:
class CustomListView extends StatefulWidget {
const CustomListView({
Key? key,
required this.ctrl,
}) : super(key: key);
final ScrollController ctrl;
@override
State<CustomListView> createState() => _CustomListViewState();
}
class _CustomListViewState extends State<CustomListView> {
late final ScrollController ctrl;
double position = 0.0;
@override
void initState() {
// TODO: implement initState
super.initState();
ctrl = widget.ctrl;
/*
ScrollController()
..addListener(() {
print(ctrl.offset);
setState((){
position = ctrl.offset;
});
});
*/
}
↓And in the outer MyApp declare a ScrollController and pass it to the CustomListView.
void main() {
runApp(
MyApp(),
);
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey listViewKey = GlobalKey();
late final ScrollController ctrl;
...
////////////////////////////////////////////////////
//in the build method of _MyAppState
Expanded(
child: CustomListView(
key: listViewKey,
ctrl: ctrl,
),
),
Now we can control the scrolling of the CustomListView from the outer MyApp, but for that we need to modify the CustomListView definition.
I think there are situations where we can't change the code, such as when the CustomListView is not our own.
If so, is there a way to control the CustomListView's scrolling and get the scroll position from the outer MyApp? Does it mean that it is impossible because there is no way?
It just came to my mind, could NotificationListner/ScrollNotification be the solution? Or if there is another way, please let me know.
CodePudding user response:
You can access the scrollController inside _CustomListViewState
with the listViewKey
that you provided to the CustomListView
widget like this:
ScrollController controller = (listViewKey.currentState as _CustomListViewState).ctrl
You may need to remove _
if the _CustomListViewState
is inside another file.
If you wrote the CustomListView
then it is best practice to accept an external scrollController. If not provided externally then you can create an instance of scrollController inside CustomListView
.