🌊 PullMeDown
The Ultimate Liquid Pull-to-Refresh Experience for Flutter

Minimalist. Fluid. Professional.
Replace the boring standard loader with a stunning liquid elastic animation.
📸 Visual Showcase
Experience the fluid animation in various themes.
| Light Mode | Dark Mode | Custom Colors |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
✨ Key Features
-
🦄 Unique Aesthetic
Stands out with a premium Pinterest-style elastic curve that feels organic and responsive. -
🎨 Infinite Customization
Full control over Liquid Color, Icon Color, and even user Custom Widgets (Lottie, Rive, etc.). -
🤯 Haptic Feedback
Built-in support for subtle Haptic Vibrations on refresh triggers for a tactile feel. -
🚀 Native Performance
Optimized for 60 FPS on both Android (ClampingScrollPhysics) and iOS (BouncingScrollPhysics). -
🌙 Dark Mode Ready
Automatically adapts contrast and colors to look great in any theme.
📦 Installation
Run this command in your terminal:
flutter pub add pull_me_down
Or add it manually to pubspec.yaml:
dependencies:
pull_me_down: ^0.0.1
🚀 Usage
Wrap any scrollable widget (ListView, GridView, SingleChildScrollView) with PullMeDown.
import 'package:pull_me_down/pull_me_down.dart';
Scaffold(
body: PullMeDown(
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
// Optional: Customize everything!
refreshColor: Colors.teal,
refreshIconColor: Colors.white,
child: ListView.builder(
itemCount: 20,
itemBuilder: (ctx, i) => ListTile(title: Text("Item $i")),
),
),
)
🛠 Advanced Configuration
| Property | Type | Description |
|---|---|---|
onRefresh |
Future Function() |
Required. The async logic to run when refreshed. |
refreshColor |
Color |
The main background color of the liquid shape. |
refreshIconColor |
Color? |
Custom color for the spinner/arrow. Defaults to auto-contrast. |
loadingIndicator |
Widget? |
Provide a custom widget (e.g. CircularProgressIndicator) to replace the default spinner. |
refreshTriggerPullDistance |
double |
Distance to pull before refresh triggers (Default: 100.0). |
refreshIndicatorExtent |
double |
Height of the container while refreshing (Default: 80.0). |
💡 Troubleshooting & Tips
🛑 List Not Scrolling?
If your list is empty, the PullMeDown gesture might not work because the Flutter Scrollable needs content to scroll. Fix it by ensuring your empty state is scrollable:
SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(), // <--- IMPORTANT
child: Container(
height: MediaQuery.of(context).size.height,
child: Text("Nothing to see here!"),
),
)
🤝 Contributing
Contributions are welcome! If you find a bug or want a feature, please open an issue.
- Fork the Project
- Create your Feature Branch
- Commit your Changes
- Push to the Branch
- Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
.png)
.png)
.png)
.png)
.png)
.png)