1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/material.dart'; |
6 | |
7 | /// Flutter code sample for [ScrollController]. |
8 | |
9 | void main() => runApp(const ScrollControllerDemo()); |
10 | |
11 | class ScrollControllerDemo extends StatefulWidget { |
12 | const ScrollControllerDemo({super.key}); |
13 | |
14 | @override |
15 | State<ScrollControllerDemo> createState() => _ScrollControllerDemoState(); |
16 | } |
17 | |
18 | class _ScrollControllerDemoState extends State<ScrollControllerDemo> { |
19 | late final ScrollController _controller; |
20 | bool isScrolling = false; |
21 | |
22 | void _handleScrollChange() { |
23 | if (isScrolling != _controller.position.isScrollingNotifier.value) { |
24 | setState(() { |
25 | isScrolling = _controller.position.isScrollingNotifier.value; |
26 | }); |
27 | } |
28 | } |
29 | |
30 | void _handlePositionAttach(ScrollPosition position) { |
31 | // From here, add a listener to the given ScrollPosition. |
32 | // Here the isScrollingNotifier will be used to inform when scrolling starts |
33 | // and stops and change the AppBar's color in response. |
34 | position.isScrollingNotifier.addListener(_handleScrollChange); |
35 | } |
36 | |
37 | void _handlePositionDetach(ScrollPosition position) { |
38 | // From here, add a listener to the given ScrollPosition. |
39 | // Here the isScrollingNotifier will be used to inform when scrolling starts |
40 | // and stops and change the AppBar's color in response. |
41 | position.isScrollingNotifier.removeListener(_handleScrollChange); |
42 | } |
43 | |
44 | @override |
45 | void initState() { |
46 | _controller = ScrollController( |
47 | // These methods will be called in response to a scroll position |
48 | // being attached to or detached from this ScrollController. This happens |
49 | // when the Scrollable is built. |
50 | onAttach: _handlePositionAttach, |
51 | onDetach: _handlePositionDetach, |
52 | ); |
53 | super.initState(); |
54 | } |
55 | |
56 | @override |
57 | Widget build(BuildContext context) { |
58 | return MaterialApp( |
59 | home: Scaffold( |
60 | appBar: AppBar( |
61 | title: Text(isScrolling ? 'Scrolling' : 'Not Scrolling' ), |
62 | backgroundColor: |
63 | isScrolling |
64 | ? Colors.green[800]!.withOpacity(.85) |
65 | : Colors.redAccent[700]!.withOpacity(.85), |
66 | ), |
67 | // ListView.builder works very similarly to this example with |
68 | // CustomScrollView & SliverList. |
69 | body: CustomScrollView( |
70 | // Provide the scroll controller to the scroll view. |
71 | controller: _controller, |
72 | slivers: <Widget>[ |
73 | SliverList.builder( |
74 | itemCount: 50, |
75 | itemBuilder: (_, int index) { |
76 | return Padding( |
77 | padding: const EdgeInsets.all(8.0), |
78 | child: Center( |
79 | child: DecoratedBox( |
80 | decoration: BoxDecoration( |
81 | color: Colors.blueGrey[50], |
82 | boxShadow: const <BoxShadow>[ |
83 | BoxShadow(color: Colors.black12, offset: Offset(5, 5), blurRadius: 5), |
84 | ], |
85 | borderRadius: const BorderRadius.all(Radius.circular(10)), |
86 | ), |
87 | child: Padding( |
88 | padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 20.0), |
89 | child: Text('Item $index' ), |
90 | ), |
91 | ), |
92 | ), |
93 | ); |
94 | }, |
95 | ), |
96 | ], |
97 | ), |
98 | ), |
99 | ); |
100 | } |
101 | } |
102 | |