import 'package:flutter/material.dart'; import 'package:unibo_android/src/rust/api/simple.dart'; import 'package:unibo_android/src/rust/frb_generated.dart'; import 'package:flutter/material.dart'; /// Flutter code sample for [ScrollController] & [ScrollNotification]. void main() => runApp(const ScrollNotificationDemo()); class ScrollNotificationDemo extends StatefulWidget { const ScrollNotificationDemo({super.key}); @override State createState() => _ScrollNotificationDemoState(); } class _ScrollNotificationDemoState extends State { ScrollNotification? _lastNotification; late final ScrollController _controller; bool _useController = true; // This method handles the notification from the ScrollController. void _handleControllerNotification() { print('Notified through the scroll controller.'); // Access the position directly through the controller for details on the // scroll position. } // This method handles the notification from the NotificationListener. bool _handleScrollNotification(ScrollNotification notification) { print('Notified through scroll notification.'); // The position can still be accessed through the scroll controller, but // the notification object provides more details about the activity that is // occurring. if (_lastNotification.runtimeType != notification.runtimeType) { setState(() { // Call set state to respond to a change in the scroll notification. _lastNotification = notification; }); } // Returning false allows the notification to continue bubbling up to // ancestor listeners. If we wanted the notification to stop bubbling, // return true. return false; } @override void initState() { _controller = ScrollController(); if (_useController) { // When listening to scrolling via the ScrollController, call // `addListener` on the controller. _controller.addListener(_handleControllerNotification); } super.initState(); } @override Widget build(BuildContext context) { // ListView.separated works very similarly to this example with // CustomScrollView & SliverList. Widget body = CustomScrollView( // Provide the scroll controller to the scroll view. controller: _controller, slivers: [ SliverList.separated( itemCount: 50, itemBuilder: (_, int index) { return Padding( padding: const EdgeInsets.symmetric( vertical: 8.0, horizontal: 20.0, ), child: Text('Item $index'), ); }, separatorBuilder: (_, __) => const Divider( indent: 20, endIndent: 20, thickness: 2, ), ), ], ); if (!_useController) { // If we are not using a ScrollController to listen to scrolling, // let's use a NotificationListener. Similar, but with a different // handler that provides information on what scrolling is occurring. body = NotificationListener( onNotification: _handleScrollNotification, child: body, ); } return MaterialApp( theme: ThemeData.from( useMaterial3: true, colorScheme: ColorScheme.fromSeed(seedColor: Colors.blueGrey), ), home: Scaffold( appBar: AppBar( title: const Text('Listening to a ScrollPosition'), bottom: PreferredSize( preferredSize: const Size.fromHeight(70), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ if (!_useController) Text('Last notification: ${_lastNotification.runtimeType}'), if (!_useController) const SizedBox.square(dimension: 10), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('with:'), Radio( value: true, groupValue: _useController, onChanged: _handleRadioChange, ), const Text('ScrollController'), Radio( value: false, groupValue: _useController, onChanged: _handleRadioChange, ), const Text('NotificationListener'), ], ), ], ), ), ), body: body, ), ); } void _handleRadioChange(bool? value) { if (value == null) { return; } if (value != _useController) { setState(() { // Respond to a change in selected radio button, and add/remove the // listener to the scroll controller. _useController = value; if (_useController) { _controller.addListener(_handleControllerNotification); } else { _controller.removeListener(_handleControllerNotification); } }); } } @override void dispose() { _controller.removeListener(_handleControllerNotification); super.dispose(); } }