Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import 'dart:math';
- import 'package:flutter/gestures.dart';
- import 'package:flutter/material.dart';
- // Credit: https://stackoverflow.com/a/66066321/7279624
- // This SO post lay out the fundamentals of this web-like scrolling widget and I completed it with animations and scrollbar.
- class WebSingleChildScrollView extends StatefulWidget {
- final Widget child;
- WebSingleChildScrollView({Key key, @required this.child})
- : assert(child != null),
- super(key: key);
- @override
- State<StatefulWidget> createState() => WebSingleChildScrollViewState();
- }
- class WebSingleChildScrollViewState extends State<WebSingleChildScrollView> {
- final _controller = ScrollController();
- double _rememberedOffset = 0;
- static const int _animationDuration = 200;
- @override
- Widget build(BuildContext context) {
- return Listener(
- // Listener listens to the pointer events
- onPointerSignal: (pointerSignal) {
- // If the mouse wheel turning event is sent
- if (pointerSignal is PointerScrollEvent) {
- // Calculate the new scroll offset
- // If an animation was going on, [_animateToPosition] is not going to be the same as [_controller.offset]
- // therefore the offset change will be larger (or smaller) than [ps.scrollDelta.dy].
- // We also know that animation duration is constant, therefore, the animation will be faster (or slower).
- final newOffset = _rememberedOffset + pointerSignal.scrollDelta.dy;
- // Adjust new offset according to the top and bottom. And remember it.
- _rememberedOffset = pointerSignal.scrollDelta.dy.isNegative ? max(0, newOffset) : min(_controller.position.maxScrollExtent, newOffset);
- // Animate the scroll
- _controller.animateTo(_rememberedOffset, curve: Curves.easeOut, duration: const Duration(milliseconds: _animationDuration));
- }
- },
- child: NotificationListener(
- // This listener is to always keep [_rememberedOffset] updated after scroll events.
- // This is for the scrollbar to be able to update [_rememberedOffset]
- // This could maybe also cover other programmatic scroll scenarios.
- onNotification: (scrollNotification) {
- // When a scrolling concludes, update the [_rememberedOffset] to the current value
- if (scrollNotification is ScrollEndNotification) {
- _rememberedOffset = _controller.offset;
- }
- // Do not consume the event
- return false;
- },
- child: Scrollbar(
- // Fully intractable, always-visible scrollbar.
- isAlwaysShown: true,
- controller: _controller,
- showTrackOnHover: true,
- child: SingleChildScrollView(
- controller: _controller,
- physics: NeverScrollableScrollPhysics(),
- child: widget.child,
- ),
- ),
- ),
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement