silky_scroll 2.6.0
silky_scroll: ^2.6.0 copied to clipboard
Silky Scroll is a package developed in Flutter to provide a smooth scrolling experience.
Silky Scroll #
SilkyScroll is a Flutter package that provides natural and smooth scroll animations for mouse wheel, trackpad, and touch inputs.
✨ SilkyScroll ↔ Default
Features #
- Smooth Scroll Animation — Interpolates mouse wheel input for seamless scrolling
- Smart Input Detection — Automatically detects mouse, trackpad, and touch to apply appropriate physics
- Edge Locking & Nested Forwarding — Locks scrolling at boundaries and automatically forwards touch/trackpad deltas to the parent scroll view
- Stretch Effect — Supports Android stretch and iOS bounce overscroll effects
- Horizontal Scroll — Supports both horizontal and vertical directions
- Preset Widgets — Drop-in
SilkyListView,SilkyGridView,SilkyCustomScrollView,SilkySingleChildScrollViewwith zero boilerplate - All Platforms — Android, iOS, Web, Windows, macOS, Linux
Getting Started #
flutter pub add silky_scroll
Basic Usage #
Simply wrap your scrollable widget with SilkyScroll.
SilkyScroll(
builder: (context, controller, physics, pointerDeviceKind) => ListView(
controller: controller,
physics: physics,
children: [...],
),
)
Preset Widgets #
Preset widgets are drop-in replacements for Flutter's scrollable widgets. They eliminate the builder boilerplate by automatically wiring controller and physics internally.
| Preset Widget | Wraps |
|---|---|
SilkyListView |
ListView |
SilkyListView.builder |
ListView.builder |
SilkyListView.separated |
ListView.separated |
SilkyGridView |
GridView |
SilkyGridView.builder |
GridView.builder |
SilkyGridView.count |
GridView.count |
SilkyGridView.extent |
GridView.extent |
SilkyCustomScrollView |
CustomScrollView |
SilkySingleChildScrollView |
SingleChildScrollView |
Before (builder pattern) #
SilkyScroll(
builder: (context, controller, physics, _) => ListView.builder(
controller: controller,
physics: physics,
itemCount: 100,
itemBuilder: (context, i) => ListTile(title: Text('Item $i')),
),
)
After (preset) #
SilkyListView.builder(
itemCount: 100,
itemBuilder: (context, i) => ListTile(title: Text('Item $i')),
)
SilkyCustomScrollView #
SilkyCustomScrollView(
slivers: [
SliverAppBar(title: Text('Header')),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) => ListTile(title: Text('Item $i')),
childCount: 50,
),
),
],
)
SilkySingleChildScrollView #
SilkySingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(children: [...]),
)
Customizing SilkyScroll behavior #
Preset widgets accept all SilkyScroll parameters directly, or via a shared SilkyScrollConfig:
// Individual parameters
SilkyListView.builder(
scrollSpeed: 1.5,
animationCurve: Curves.easeOutCubic,
itemCount: 100,
itemBuilder: (context, i) => Text('$i'),
)
// Shared config (overrides individual parameters when provided)
final config = SilkyScrollConfig(scrollSpeed: 1.5);
SilkyListView.builder(
silkyConfig: config,
itemCount: 100,
itemBuilder: (context, i) => Text('$i'),
)
Detecting pointer device kind #
SilkyListView.builder(
itemCount: 100,
itemBuilder: (context, i) => Text('$i'),
onPointerDeviceKindChanged: (kind) {
// PointerDeviceKind.mouse, .trackpad, .touch
},
)
Custom Usage #
You can connect an external ScrollController and fine-tune animation properties.
class _ScrollExampleState extends State<ScrollExample> {
late final ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SilkyScroll(
controller: _scrollController,
physics: const BouncingScrollPhysics(),
silkyScrollDuration: const Duration(milliseconds: 2000),
scrollSpeed: 1.5,
animationCurve: Curves.easeOutQuart,
direction: Axis.vertical,
builder: (context, controller, physics, pointerDeviceKind) {
return ListView.builder(
controller: controller,
physics: physics,
itemCount: 50,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
);
},
),
);
}
}
Using SilkyScrollConfig #
You can share the same configuration across multiple SilkyScroll widgets.
const config = SilkyScrollConfig(
silkyScrollDuration: Duration(milliseconds: 1000),
scrollSpeed: 1.5,
animationCurve: Curves.easeOutCubic,
enableStretchEffect: true,
);
SilkyScroll.fromConfig(
config: config,
builder: (context, controller, physics, pointerDeviceKind) => ListView(...),
)
Web: Overscroll Behavior Control #
On web, SilkyScroll automatically sets overscroll-behavior-x: none while the widget is mounted (controlled by the blockWebOverscrollBehaviorX parameter, default true). This blocks browser back/forward swipe gestures.
When all SilkyScroll widgets with blocking enabled are disposed, the CSS is automatically restored to auto.
Per-widget control #
// Disable browser swipe blocking for this widget
SilkyScroll(
blockWebOverscrollBehaviorX: false,
builder: (context, controller, physics, pointerDeviceKind) => ListView(...),
)
Global control #
You can also set a global block flag that persists independently of widgets:
import 'package:silky_scroll/silky_scroll.dart';
// Force block browser swipe gestures globally
SilkyScrollGlobalManager.instance
.setBlockOverscrollBehaviorX(true);
// Remove the global block (widgets may still block individually)
SilkyScrollGlobalManager.instance
.setBlockOverscrollBehaviorX(false);
The actual CSS is set to none when any widget requests blocking or the global flag is true. It reverts to auto only when both are inactive.
On non-web platforms this is a no-op.
Parameters #
| Parameter | Type | Default | Description |
|---|---|---|---|
controller |
ScrollController? |
null |
External scroll controller |
silkyScrollDuration |
Duration |
850ms |
Scroll animation duration |
scrollSpeed |
double |
1 |
Scroll speed multiplier |
animationCurve |
Curve |
Curves.easeOutQuart |
Animation curve |
direction |
Axis |
vertical |
Scroll direction |
physics |
ScrollPhysics |
ScrollPhysics() |
Scroll physics |
edgeLockingDelay |
Duration |
650ms |
Lock delay after reaching edge |
overScrollingLockingDelay |
Duration |
700ms |
Overscroll lock delay |
enableStretchEffect |
bool |
true |
Overscroll stretch effect |
edgeForwardingMode |
EdgeForwardingMode |
EdgeForwardingMode.sameAxisOnly |
Edge delta forwarding to ancestor |
decayLogFactor |
double |
12 |
Smooth-scroll convergence speed |
blockWebOverscrollBehaviorX |
bool |
true |
Block browser swipe on web |
setManualPointerDeviceKind |
Function? |
null |
Manual pointer device override |
onScroll |
Function(double)? |
null |
Scroll event callback |
onEdgeOverScroll |
Function(double)? |
null |
Edge overscroll callback |
debugMode |
bool |
false |
Debug logging |
License #
MIT