From 94c4222f2bd59d91554062953ea899b64629a02c Mon Sep 17 00:00:00 2001 From: Ali Ghassemi Date: Fri, 17 Jun 2016 14:44:00 -0700 Subject: [PATCH] Few overscroll glow fixes. (#4610) Fixes #4169 and also now overscroll indicator is dismissed the moment user scrolls in the opposite direction (#4603) but the bounce overscroll that happens behind the scene and is clamped in the indicator is still problematic and needs to be fixed. However these fixes are orthogonal to that. Also closes #4127 as I verified the timeout feature (reduced the duration to 500ms to be closer to Android behaviour) --- .../src/material/overscroll_indicator.dart | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/material/overscroll_indicator.dart b/packages/flutter/lib/src/material/overscroll_indicator.dart index 1d312ba9de..08a0b2e920 100644 --- a/packages/flutter/lib/src/material/overscroll_indicator.dart +++ b/packages/flutter/lib/src/material/overscroll_indicator.dart @@ -13,7 +13,7 @@ const double _kMaxIndicatorExtent = 64.0; const double _kMinIndicatorOpacity = 0.0; const double _kMaxIndicatorOpacity = 0.25; const Duration _kIndicatorHideDuration = const Duration(milliseconds: 200); -const Duration _kIndicatorTimeoutDuration = const Duration(seconds: 1); +const Duration _kIndicatorTimeoutDuration = const Duration(milliseconds: 500); final Tween _kIndicatorOpacity = new Tween(begin: 0.0, end: 0.3); class _Painter extends CustomPainter { @@ -132,7 +132,10 @@ class _OverscrollIndicatorState extends State { void _hide() { _hideTimer?.cancel(); _hideTimer = null; - _extentAnimation.reverse(); + // Gaurding _hide() being called while indicator is already animating. + if (!_extentAnimation.isAnimating) { + _extentAnimation.reverse(); + } } void _updateState(ScrollableState scrollable) { @@ -151,12 +154,15 @@ class _OverscrollIndicatorState extends State { void _onScrollUpdated(ScrollableState scrollable) { final double value = scrollable.scrollOffset; - if ((value < _minScrollOffset || value > _maxScrollOffset) && - ((value - _scrollOffset).abs() > kPixelScrollTolerance.distance)) { - _hideTimer?.cancel(); - _hideTimer = new Timer(_kIndicatorTimeoutDuration, _hide); - // Changing the animation's value causes an implicit setState(). - _extentAnimation.value = value < _minScrollOffset ? _minScrollOffset - value : value - _maxScrollOffset; + if (_isOverscroll(value)) { + _refreshHideTimer(); + // Hide the indicator as soon as user starts scrolling in the reverse direction of overscroll. + if (_isReverseScroll(value)) { + _hide(); + } else { + // Changing the animation's value causes an implicit setState(). + _extentAnimation.value = value < _minScrollOffset ? _minScrollOffset - value : value - _maxScrollOffset; + } } _updateState(scrollable); } @@ -166,6 +172,21 @@ class _OverscrollIndicatorState extends State { _hide(); } + void _refreshHideTimer() { + _hideTimer?.cancel(); + _hideTimer = new Timer(_kIndicatorTimeoutDuration, _hide); + } + + bool _isOverscroll(double scrollOffset) { + return (scrollOffset < _minScrollOffset || scrollOffset > _maxScrollOffset) && + ((scrollOffset - _scrollOffset).abs() > kPixelScrollTolerance.distance); + } + + bool _isReverseScroll(double scrollOffset) { + final double delta = _scrollOffset - scrollOffset; + return scrollOffset < _minScrollOffset ? delta < 0 : delta > 0; + } + bool _handleScrollNotification(ScrollNotification notification) { if (config.scrollableKey == null || config.scrollableKey == notification.scrollable.config.key) { final ScrollableState scrollable = notification.scrollable;