A high-performance Flutter widget for creating interactive liquid ripple effects on images and widgets using custom GLSL shaders.
🚀 Features
- 💧 Realistic Liquid Simulation: Physics-inspired ripple wave propagation powered by custom GLSL fragment shaders.
- ⚡ 60 FPS Performance: Hardware-accelerated rendering on mobile, web, and desktop without third-party animation libraries.
- 👆 Interactive & Gesture-Ready: Tap or drag to generate fluid wave interference.
- 🎮 Programmatic Control: Trigger or clear waves on demand with
RippleController. - 🖼️ Flexible Image Providers: Seamlessly works with
AssetImage,NetworkImage,MemoryImage,FileImage, or rawui.Image. - 🔋 Battery Efficient: Intelligent rendering stops running animation frames when there are no active ripples.
📸 Demo
|
|
📦 Getting Started
Add flutter_ripple_effect to your pubspec.yaml:
flutter pub add flutter_ripple_effect
or add it directly:
dependencies:
flutter_ripple_effect: ^1.0.0
Import it in your Dart code:
import 'package:flutter_ripple_effect/flutter_ripple_effect.dart';
💻 Usage
1. Basic Example
Wrap your image with RippleEffect:
import 'package:flutter/material.dart';
import 'package:flutter_ripple_effect/flutter_ripple_effect.dart';
class MyRippleWidget extends StatelessWidget {
const MyRippleWidget({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: RippleEffect(
imageProvider: const AssetImage('assets/my_photo.jpg'),
borderRadius: BorderRadius.circular(20),
power: 1.2,
),
);
}
}
2. Programmatic Control (RippleController)
Trigger ripples from external events, buttons, or sensor inputs:
class ControlledRippleExample extends StatefulWidget {
const ControlledRippleExample({super.key});
@override
State<ControlledRippleExample> createState() => _ControlledRippleExampleState();
}
class _ControlledRippleExampleState extends State<ControlledRippleExample> {
final RippleController _controller = RippleController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _triggerCenterWave() {
// Add ripple at normalized coordinates (0.5, 0.5) with power 1.5
_controller.addRipple(const Offset(0.5, 0.5), power: 1.5);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
RippleEffect(
controller: _controller,
imageProvider: const NetworkImage('https://picsum.photos/600/600'),
borderRadius: BorderRadius.circular(16),
),
ElevatedButton(
onPressed: _triggerCenterWave,
child: const Text('Drop Ripple'),
),
TextButton(
onPressed: () => _controller.clear(),
child: const Text('Clear Ripples'),
),
],
);
}
}
3. Low-level Canvas Painting (RipplePainter)
If you manage your own custom canvas render loop:
CustomPaint(
painter: RipplePainter(
program: fragmentProgram, // ui.FragmentProgram
image: myUiImage, // ui.Image
ripples: activeRipples, // List<RippleModel>
time: elapsedTimeSeconds, // double
),
size: Size(width, height),
)
⚙️ Properties
| Property | Type | Default | Description |
|---|---|---|---|
imageProvider |
ImageProvider? |
null |
Image provider (AssetImage, NetworkImage, etc.). |
image |
ui.Image? |
null |
Directly pass a decoded ui.Image. |
controller |
RippleController? |
null |
Controller for programmatic trigger & clear actions. |
power |
double |
1.0 |
Default ripple distortion power. |
maxRipples |
int |
5 |
Maximum concurrent ripples supported (up to 5). |
rippleDuration |
Duration |
2500ms |
Duration each ripple persists before fading out. |
enableTouch |
bool |
true |
Whether user taps/touches generate ripples. |
onTap |
Function(Offset, Offset)? |
null |
Callback giving (normalizedPos, localPos). |
borderRadius |
BorderRadius? |
null |
Border radius for clipping the effect. |
placeholder |
WidgetBuilder? |
null |
Widget displayed while shader or image is loading. |
errorBuilder |
Widget Function(context, error)? |
null |
Widget displayed if asset loading fails. |
🛠️ Example App
Check out the full example in the example/ directory for a complete demo project.
📄 License
MIT License - see the LICENSE file for details.
Libraries
- flutter_ripple_effect
- A high-performance Flutter package for creating interactive liquid ripple effects on images and widgets using custom GLSL shaders.