RippleRevealButton class
Botón animado con efecto ripple/circular reveal que alterna entre dos widgets.
Genera un círculo que se expande desde el punto del toque (tap) hasta cubrir
el área del botón, creando una transición suave entre dos contenidos
(widgetA y widgetB) y dos esquemas de color (backgroundColorA/B y rippleColorA/B).
Es ideal para toggles, switches personalizados y cualquier control donde quieras comunicar el cambio de estado con un feedback visual claro y moderno.
Cómo funciona
- El fondo del botón cambia entre
backgroundColorAybackgroundColorBsegún el estado seleccionado. - El ripple dibuja un círculo del color
rippleColorA/B(dependiendo del estado actual) que nace en el punto del tap y se expande hasta cubrir el botón. - El contenido alterna entre
widgetA(estado seleccionado) ywidgetB(no seleccionado).
Buenas prácticas
- Usa colores contrastantes entre fondo y ripple para potenciar el efecto.
- Ajusta
radiuspara esquinas más suaves (mínimo 2.0). - Si vas a controlar el estado desde fuera, usa
selectedy actualízalo ensetState.
Ejemplo básico
RippleRevealButton(
widgetA: const Text('ON', style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold)),
widgetB: const Text('OFF', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
backgroundColorA: Colors.black,
backgroundColorB: Colors.white,
rippleColorA: Colors.white,
rippleColorB: Colors.black,
onPressed: () { debugPrint('Toggled!'); },
)
Ejemplo con personalización visual
RippleRevealButton(
widgetA: const Icon(Icons.check, color: Colors.white),
widgetB: const Icon(Icons.close, color: Colors.red),
backgroundColorA: Colors.green.shade700,
backgroundColorB: Colors.grey.shade200,
rippleColorA: Colors.greenAccent,
rippleColorB: Colors.grey,
height: 52,
radius: 12,
padding: const EdgeInsets.symmetric(horizontal: 20),
alignment: Alignment.center,
onPressed: () { /* tu lógica */ },
)
Ejemplo con control externo del estado
class MyToggle extends StatefulWidget {
const MyToggle({super.key});
@override
State<MyToggle> createState() => _MyToggleState();
}
class _MyToggleState extends State<MyToggle> {
bool active = false;
@override
Widget build(BuildContext context) {
return RippleRevealButton(
selected: active,
widgetA: const Text('Activo'),
widgetB: const Text('Inactivo'),
backgroundColorA: Colors.blue,
backgroundColorB: Colors.black12,
rippleColorA: Colors.white,
rippleColorB: Colors.black45,
onPressed: () {
setState(() => active = !active);
},
);
}
}
Ejemplo con borde decorativo
RippleRevealButton(
widgetA: const Text('Premium', style: TextStyle(color: Colors.amber)),
widgetB: const Text('Básico'),
backgroundColorA: Colors.black,
backgroundColorB: Colors.white,
rippleColorA: Colors.amber,
rippleColorB: Colors.black,
border: Border.all(color: Colors.amber, width: 2),
radius: 16,
height: 56,
onPressed: () { /* upgrade */ },
)
Notas
- Este widget fija el cursor a
clicken desktop (MouseRegion) para mejor UX. - El ripple nace del tap exacto usando coordenadas locales del
RenderBox. durationcontrola la velocidad de la expansión circular.
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- RippleRevealButton
Constructors
- RippleRevealButton({Key? key, required Widget widgetA, required Widget widgetB, Color backgroundColorA = Colors.black, Color backgroundColorB = Colors.white, Color rippleColorA = Colors.white, Color rippleColorB = Colors.black, required VoidCallback onPressed, double height = 48, double radius = 2, Duration duration = const Duration(milliseconds: 300), bool? selected, BoxBorder? border, EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 16), AlignmentGeometry alignment = Alignment.center})
-
Crea un RippleRevealButton.
const
Properties
- alignment → AlignmentGeometry
-
Alineación del contenido dentro del botón.
final
- backgroundColorA → Color
-
Color de fondo cuando está seleccionado.
final
- backgroundColorB → Color
-
Color de fondo cuando NO está seleccionado.
final
- border → BoxBorder?
-
Borde decorativo opcional (no afecta el área de toque).
final
- duration → Duration
-
Duración de la animación del ripple.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
- height → double
-
Altura del botón en píxeles.
final
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- onPressed → VoidCallback
-
Callback al presionar el botón (se ejecuta antes del cambio interno).
final
- padding → EdgeInsetsGeometry
-
Padding interno del contenido.
final
- radius → double
-
Radio de las esquinas del botón (mínimo 2.0).
final
- rippleColorA → Color
-
Color del ripple cuando está seleccionado.
final
- rippleColorB → Color
-
Color del ripple cuando NO está seleccionado.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- selected → bool?
-
Estado inicial del botón (opcional, control externo).
final
- widgetA → Widget
-
Widget mostrado cuando está seleccionado.
final
- widgetB → Widget
-
Widget mostrado cuando NO está seleccionado.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → State< RippleRevealButton> -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited