Advertisement
Guest User

web_single_child_scroll_view

a guest
May 25th, 2021
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 2.91 KB | None | 0 0
  1. import 'dart:math';
  2.  
  3. import 'package:flutter/gestures.dart';
  4. import 'package:flutter/material.dart';
  5.  
  6. // Credit: https://stackoverflow.com/a/66066321/7279624
  7. // This SO post lay out the fundamentals of this web-like scrolling widget and I completed it with animations and scrollbar.
  8. class WebSingleChildScrollView extends StatefulWidget {
  9.   final Widget child;
  10.  
  11.   WebSingleChildScrollView({Key key, @required this.child})
  12.       : assert(child != null),
  13.         super(key: key);
  14.  
  15.   @override
  16.   State<StatefulWidget> createState() => WebSingleChildScrollViewState();
  17. }
  18.  
  19. class WebSingleChildScrollViewState extends State<WebSingleChildScrollView> {
  20.   final _controller = ScrollController();
  21.   double _rememberedOffset = 0;
  22.  
  23.   static const int _animationDuration = 200;
  24.  
  25.   @override
  26.   Widget build(BuildContext context) {
  27.     return Listener(
  28.       // Listener listens to the pointer events
  29.       onPointerSignal: (pointerSignal) {
  30.         // If the mouse wheel turning event is sent
  31.         if (pointerSignal is PointerScrollEvent) {
  32.           // Calculate the new scroll offset
  33.           // If an animation was going on, [_animateToPosition] is not going to be the same as [_controller.offset]
  34.           // therefore the offset change will be larger (or smaller) than [ps.scrollDelta.dy].
  35.           // We also know that animation duration is constant, therefore, the animation will be faster (or slower).
  36.           final newOffset = _rememberedOffset + pointerSignal.scrollDelta.dy;
  37.  
  38.           // Adjust new offset according to the top and bottom. And remember it.
  39.           _rememberedOffset = pointerSignal.scrollDelta.dy.isNegative ? max(0, newOffset) : min(_controller.position.maxScrollExtent, newOffset);
  40.  
  41.           // Animate the scroll
  42.           _controller.animateTo(_rememberedOffset, curve: Curves.easeOut, duration: const Duration(milliseconds: _animationDuration));
  43.         }
  44.       },
  45.       child: NotificationListener(
  46.         // This listener is to always keep [_rememberedOffset] updated after scroll events.
  47.         // This is for the scrollbar to be able to update [_rememberedOffset]
  48.         // This could maybe also cover other programmatic scroll scenarios.
  49.         onNotification: (scrollNotification) {
  50.           // When a scrolling concludes, update the [_rememberedOffset] to the current value
  51.           if (scrollNotification is ScrollEndNotification) {
  52.             _rememberedOffset = _controller.offset;
  53.           }
  54.  
  55.           // Do not consume the event
  56.           return false;
  57.         },
  58.         child: Scrollbar(
  59.           // Fully intractable, always-visible scrollbar.
  60.           isAlwaysShown: true,
  61.           controller: _controller,
  62.           showTrackOnHover: true,
  63.           child: SingleChildScrollView(
  64.             controller: _controller,
  65.             physics: NeverScrollableScrollPhysics(),
  66.             child: widget.child,
  67.           ),
  68.         ),
  69.       ),
  70.     );
  71.   }
  72. }
  73.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement