silky_scroll 2.4.1
silky_scroll: ^2.4.1 copied to clipboard
Silky Scroll is a package developed in Flutter to provide a smooth scrolling experience.
Changelog #
All notable changes to this project will be documented in this file.
2.4.1 #
Fixed #
- Bounce-back freeze on BouncingScrollPhysics: Fixed a bug where lifting the finger while the scroll offset was in the overscroll region (iOS bounce) could permanently freeze the scroll position.
_checkEdgeLockOnTouchUpnow skips_setBlocked(true)when the offset is outside the normal scroll extent, preventingcreateBallisticSimulation()from being suppressed by the blocking state before Flutter'sgoBallistic()fires. - Bounce-back recovery on unlock:
_unlockScrollnow triggersgoBallistic(0.0)when physics were blocked and the offset is still in the overscroll region, ensuring the bounce-back simulation restarts after the edge-lock timer expires.
2.4.0 #
Breaking #
- Removed
recoilDurationSec: TherecoilDurationSecparameter andkDefaultRecoilDurationSecconstant have been removed. Bounce-back animations are now delegated to Flutter's nativeBouncingScrollPhysicsballistic simulation. - Removed
SilkyEdgeDetector: Edge detection logic has been inlined intoSilkyScrollState. - Removed
SilkyScrollMousePointerManager: Fully replaced bySilkyScrollGlobalManager. handleTouchScrollsplit:handleTouchScrollhas been split intohandleTrackpadScrollandhandleTouchDragScrollfor separate handling of trackpad and touch drag inputs.silkyScrollDurationdefault changed: From700msto850ms.
Added #
EdgeForwardingModeenum: New enum (none,sameAxisOnly,always) controlling how edge-locked scroll deltas are forwarded to ancestor scrollables. Exported from barrel file.edgeForwardingModeparameter: Added toSilkyScrollConfigandSilkyScrollwidget (default:EdgeForwardingMode.sameAxisOnly).- Native bounce delegation:
triggerNativeBounce()delegates overscroll bounce-back to Flutter's nativeBouncingScrollPhysicsviagoBallistic(0.0), replacing the custom recoil animation. - Ancestor scrollable detection: Edge-locking is now skipped on BouncingScrollPhysics platforms when there is no ancestor scrollable to forward to, allowing native bounce to play normally.
Changed #
- Recoil animation replaced: Custom recoil ticker logic removed; overscroll recovery now uses Flutter's native ballistic simulation.
- Edge-locking on BouncingScrollPhysics: Physics are no longer blocked during edge-lock on iOS/macOS to preserve native bounce-back animation. Physics are only blocked dynamically when an outward delta arrives for forwarding.
- Improved gesture unlock:
_tryGestureUnlocknow requirescurrentInputSpeed > 2before recognizing an inward direction change. - Ancestor forwarding axis check: When
edgeForwardingMode == sameAxisOnly, forwarding only occurs when the ancestor shares the same scroll axis. - Renamed internal
currentScrollSpeed→currentInputSpeed,_recentDeltaSamples→_recentInputDeltaSamplesfor clarity.
Removed #
recoilDurationSecparameter andkDefaultRecoilDurationSecconstant.SilkyEdgeDetectorclass and its test file.SilkyScrollMousePointerManagerclass and its test file.isRecoilScrollstate field,onAnimationStateChanged()delegate callback, and all recoil ticker logic fromSilkyScrollAnimator.
2.3.0 #
Added #
- Nested scroll forwarding on edge lock: When an inner
SilkyScrollreaches a scroll boundary and becomes edge-locked, subsequent touch and trackpad deltas in the same (outward) direction are now forwarded to the nearest ancestorScrollable, allowing the outer scroll view to take over scrolling seamlessly.
Changed #
SilkyScrollStatenow accepts aBuildContextreference (set automatically by the widget) to locate ancestor scrollables at runtime.handleTouchScrollchecks the edge-lock phase and delta direction before deciding whether to forward to the ancestor or continue internal processing.
2.2.2 #
Fixed #
- Removed stray
printcall inSilkyScrollGlobalManager.setOverscrollBehaviorX(). - Renamed local variable
_flushWindow→flushWindowinScrollDeltaSampleAnalyzerto satisfyno_leading_underscores_for_local_identifierslint.
2.2.1 #
Changed #
- Added
Web: Overscroll Behavior Controlsection to README documentingsetOverscrollBehaviorX()API andOverscrollBehaviorXenum usage.
2.2.0 #
Breaking #
SilkyScrollGlobalManageraccess changed: Replaced factory constructor withSilkyScrollGlobalManager.instancestatic field for explicit singleton semantics.overscroll-behavior-xdefault behavior changed: Now permanently set tononeon both<html>and<body>elements at initialization, instead of temporarily blocking per scroll event via Timer.
Added #
OverscrollBehaviorXenum — type-safe CSS values (auto,none,contain) for theoverscroll-behavior-xproperty, exported from the barrel file.SilkyScrollGlobalManager.setOverscrollBehaviorX()— allows manually overriding theoverscroll-behavior-xCSS property at runtime.
Changed #
blockOverscrollBehaviorXcall timing: Now invoked only forPointerDeviceKind.trackpad, and before the delta threshold check instead of inside it.- Web helper simplified: Removed
Timer-based delay/reset logic;overscroll-behavior-xis applied once at init and can be changed explicitly viasetOverscrollBehaviorX(). - Web helper targets both root elements:
overscroll-behavior-xis now set on both<html>and<body>(previously only<body>).
Fixed #
- Fixed
_lockedEdgeDirectionnot being assigned when enteringBlockedScrollPhysics, which could cause incorrect edge-lock direction tracking.
2.1.1 #
Changed #
currentScrollSpeedcaching: Results are now cached for ~16 ms (one frame), eliminating redundantcalculateAverageSpeedcalls from_checkNeedLocking,_checkEdgeLockOnTouchUp, and_tryGestureUnlockwithin the same frame._recordDeltatrimming optimization: ReplacedremoveWhereO(n) full-scan withremoveRange(0, count)exploiting the time-sorted order of samples.calculateAverageSpeedallocation reduction: Rewrote to single-pass inline aggregation, removing 5+ intermediate list allocations (List.of,windowGroups,windowAggregates,windowSpeeds,movementSpeeds) per call.blockOverscrollBehaviorXHtmlTimer reuse: Replaced per-event cancel+recreate pattern with timestamp tracking and a single reusable Timer, reducing Timer object churn during rapid trackpad scrolling.scrollDeltaXcomparison: Replaced(scrollDeltaX * 10).toInt() != 0withscrollDeltaX.abs() >= 0.1for clarity and to avoid unnecessary float-to-int conversion.
Removed #
- Removed
recentDeltaSamplespublic getter (unused externally).
2.1.0 #
Breaking #
- Builder signature changed:
SilkyScrollWidgetBuildernow receives a 4th parameterPointerDeviceKind? pointerDeviceKind, allowing widgets to adapt their behavior based on the detected input device. - Removed bubbling option: Scroll bubbling to parent views is now seamlessly integrated into the default edge-locking logic, providing a much more natural nested-scroll experience without any configuration.
Added #
decayLogFactorparameter — controls the exponential-decay log factor for smooth-scroll convergence speed (default:12).recoilDurationSecparameter — controls the duration of the bounce-back (recoil) animation in seconds (default:0.2).setManualPointerDeviceKindcallback — allows manually overriding the detected pointer device kind for custom input handling.- Exported
kDefaultDecayLogFactorandkDefaultRecoilDurationSecconstants from barrel file.
Changed #
- Scroll bubbling is now handled automatically within the core edge-locking state machine, eliminating the need for a separate configuration option and delivering smoother transitions in nested scroll views.
- Recoil (bounce-back) animation and overshoot clamping now only activate when the widget's scroll physics is
BouncingScrollPhysics. Non-bouncing physics (e.g.ClampingScrollPhysics) no longer overshoot scroll extents or trigger recoil.
2.0.3 #
Fixed #
- Fixed
include_file_not_foundwarning in exampleanalysis_options.yamlby replacing deprecatedflutter_lintswithlints. - Removed unnecessary
package:flutter/scheduler.dartimport inSilkyScrollState(already provided bymaterial.dart). - Removed unused
package:flutter/foundation.dartimport in input handler tests. - Replaced unnecessary lambdas with tear-offs in state tests.
2.0.2 #
Changed #
- Ticker-based animation engine: Replaced per-event
controller.animateTo()with a singleTicker+jumpTo()loop using frame-rate-independent exponential smoothing. Eliminates the stutter caused by repeatedly cancelling and restarting easing curves on rapid mouse-wheel input. - Targeted rebuild: Replaced
ListenableBuilder(which rebuilt the entire widget subtree on everynotifyListeners()) with a dedicated_onPhysicsChangedlistener that callssetStateonly when theScrollPhysicsreference actually changes. - Recoil animation: Bounce-back (recoil) to edge now runs inside the same Ticker using
Curves.easeInOutSineinterpolation, avoiding a separateanimateTo()call that could conflict with ongoing scroll animations.
Fixed #
- Overscroll bounce-back stutter: Added
silkyTickerActiveflag toSilkyScrollPositionthat suppressesgoBallistic()while the Ticker is running. Previously, eachjumpTo()during overscroll triggered Flutter'sBouncingScrollPhysicsspring simulation, which fought with the Ticker every frame — causing visible jitter at both top and bottom edges.
2.0.1 #
Fixed #
onScrollandonEdgeOverScrollcallbacks were not passed fromSilkyScrollwidget toSilkyScrollState, causing them to always benull.onEdgeOverScrollwas never invoked; it is now called when mouse-wheel or touch/trackpad scroll reaches an edge.
2.0.0 #
Breaking #
- Removed
providerdependency; replaced withInheritedWidget+ListenableBuilder. - Applied Dart 3
final class/abstract interface classmodifiers to all public classes. Externalextends/implementsis no longer permitted for concrete types. - Exported
ScrollPhysicsPhaseenum from barrel file.
Added #
SilkyScrollConfig.copyWith,==,hashCode, andtoString.SilkyScrollGlobalManager.resetForTesting(@visibleForTesting).SilkyScrollWebManagerInterface.isWebPlatformfor conditional-import–based platform detection.SilkyEdgeDetector: sub-pixel edge detection using threshold instead oftoInt().- State machine
_transitionTonow guards against Timer creation after dispose. SilkyScrollController.attach/detachguard against duplicate position registration.- Test infrastructure:
test/helpers/test_helpers.dartshared utilities. - New tests for
SilkyScrollAnimator,SilkyInputHandler,SilkyScrollConfig, and integration tests (67 total, up from 24).
Changed #
kIsWebruntime branching inSilkyInputHandlerreplaced with conditional-import pattern viaisWebPlatform.ListenableBuilderrebuild scope reduced:onAnimationStateChangedno longer triggers unnecessary widget rebuilds for recoil state.- Dispose order in
SilkyScrollStatemade deterministic and safe. - Edge-detection refactored to switch expression / pattern matching (Dart 3).
SilkyScrollAnimator._handleRecoilrefactored to switch expression.- Web helper magic number
Duration(milliseconds: 700)extracted to_kOverscrollBehaviorXResetDelayconstant. - Lint configuration upgraded from
flutter_lintstopackage:lints/recommended.yamlwith custom rules. - Example restructured to
example/lib/main.dart+example/pubspec.yaml(pub.dev guideline). - README image paths updated from
Bluebar1/dyn_mouse_scrolltoDynaruid/silky_scroll.
Removed #
- Legacy duplicate source files under
lib/root (moved tolib/src/in Phase 1).
Fixed #
_unlockScrollnow correctly transitions_physicsPhaseback toScrollPhysicsPhase.normal._transitionTochecks_disposedbefore creating a new Timer.
1.0.14 #
Fixed #
- Removed usage of
Platformfromdart:iodue to compatibility issues causing errors on Safari in iOS 18.2.
1.0.12 #
Added #
- Added an option to configure whether scroll bubbling is propagated when an inner scroll view reaches its edge within nested scroll views.
1.0.6 #
Changed #
- The duration of scroll momentum transferred to the parent widget has been adjusted to behave more naturally.