Global Ripple

A fully functional, pure Dart Flutter plugin that provides a global water ripple (ink ripple) effect when the user taps anywhere in the app.

logo

This package works by wrapping your application in a provider that listens for global taps and renders ripples in an overlay-like stack, without interfering with your app's gestures.

Features

  • Global Layout: Taps anywhere in the app trigger a ripple.
  • Highly Optimized: Uses a single Ticker and CustomPainter to manage multiple ripples efficiently.
  • Zero Interference: Uses IgnorePointer and transparent hit testing to ensure your app's buttons and gestures work perfectly.
  • Customizable: Control color, radius, duration, and curve.
  • Cross-Platform: Works on Android, iOS, Web, Windows, macOS, and Linux.

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  global_ripple: ^1.0.0

Usage

Wrap your MaterialApp (or CupertinoApp) with GlobalRippleProvider. You typically need to provide a GlobalRippleController to manage the state.

import 'package:flutter/material.dart';
import 'package:global_ripple/global_ripple.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // 1. Create the controller
    final rippleController = GlobalRippleController();

    // 2. Configure default settings (Optional)
    rippleController.defaultIsRippleColor = Colors.blue.withOpacity(0.2);
    rippleController.defaultRadius = 100.0;
    rippleController.defaultDuration = const Duration(milliseconds: 600);

    // 3. Wrap your app
    return GlobalRippleProvider(
      controller: rippleController,
      child: MaterialApp(
        title: 'Global Ripple Demo',
        home: const Scaffold(
            body: Center(child: Text("Tap anywhere!"))
        ),
      ),
    );
  }
}

Advanced Usage

You can also trigger ripples programmatically using the controller:

rippleController.addRipple(
    Offset(100, 100),
    color: Colors.red.withOpacity(0.5),
    radius: 50
);

Common Questions

Does it block my buttons? No. The tap listener uses HitTestBehavior.translucent and lets events pass through. The visual ripple layer is wrapped in IgnorePointer.

Does it work with Dialogs? Yes, but since standard Dialogs are pushed to the Navigator's Overlay (which is above the MaterialApp's child), ripples might appear behind the dialog backdrop if you wrap MaterialApp. The taps are still detected globally.

License

MIT

Libraries

global_ripple