global_ripple 1.0.0
global_ripple: ^1.0.0 copied to clipboard
A Flutter plugin for global water ripple effects on tap.
example/lib/main.dart
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) {
// Create the controller.
// In a real app, you might want to keep this in a singleton or provider if you need
// to change settings dynamically from anywhere.
final rippleController = GlobalRippleController();
// Custom settings for the demo
rippleController.defaultIsRippleColor =
Colors.blueAccent.withOpacity(0.15); // ignore: deprecated_member_use
rippleController.defaultRadius = 80.0;
rippleController.defaultDuration = const Duration(milliseconds: 1000);
return GlobalRippleProvider(
controller: rippleController,
child: MaterialApp(
title: 'Global Ripple Demo',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: const MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Global Ripple Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Tap anywhere to see the ripple!',
style: TextStyle(fontSize: 18),
),
const SizedBox(height: 20),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// This button confirms that taps pass through the ripple layer.
_incrementCounter();
},
child: const Text('Tap Me (Pass-through check)'),
),
const SizedBox(height: 20),
// Example of a dialog to show it works there too (if overlay is correct)
// Note: with the current `GlobalRippleProvider` wrapping `MaterialApp`,
// ripples will show BEHIND dialogs because Dialogs are pushed to the Navigator's Overlay
// which sits *above* the MaterialApp's child.
// The user requirement "works globally" usually implies "over everything".
// To fix this, in the example we can show how to integration deeper or accept this limitation.
// Actually, `Listener` at the top of stack captures tap which is fine.
// But visually, the ripple `CustomPaint` is in the stack *below* the Navigator (and its Overlay).
// So ripples might appear under the dialog backdrop.
OutlinedButton(
onPressed: () {
showDialog(
context: context,
builder: (c) => AlertDialog(
title: const Text("Dialog Test"),
content: const Text(
"Tap outside. Does ripple show? It might be behind the dim barrier.",
),
actions: [
TextButton(
onPressed: () => Navigator.pop(c),
child: const Text("Close"),
),
],
),
);
},
child: const Text("Show Dialog"),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}