import 'package:flutter/material.dart'; class PanelToggleAffordance extends StatefulWidget { static const double _radius = 8; static const Color _activeFill = Color(0x2EFFFFFF); static const Duration _openDuration = Duration(milliseconds: 220); static const Duration _closeDuration = Duration(milliseconds: 130); final bool isOpen; final VoidCallback onTap; final String? tooltip; final EdgeInsets padding; final Widget child; const PanelToggleAffordance({ super.key, required this.isOpen, required this.onTap, required this.child, this.tooltip, this.padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 8), }); @override State createState() => _PanelToggleAffordanceState(); } class _PanelToggleAffordanceState extends State with SingleTickerProviderStateMixin { late final AnimationController _ctrl; late final Animation _t; @override void initState() { super.initState(); _ctrl = AnimationController( vsync: this, duration: PanelToggleAffordance._openDuration, reverseDuration: PanelToggleAffordance._closeDuration, value: widget.isOpen ? 1.0 : 0.0, ); _t = CurvedAnimation( parent: _ctrl, curve: Curves.easeInOutCubic, reverseCurve: Curves.easeInCubic, ); } @override void didUpdateWidget(covariant PanelToggleAffordance oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.isOpen != widget.isOpen) { if (widget.isOpen) { _ctrl.forward(); } else { _ctrl.reverse(); } } } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final inkWell = Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(PanelToggleAffordance._radius), onTap: widget.onTap, child: AnimatedBuilder( animation: _t, builder: (context, child) { final fill = Color.lerp( Colors.transparent, PanelToggleAffordance._activeFill, _t.value, )!; return Container( padding: widget.padding, decoration: BoxDecoration( borderRadius: BorderRadius.circular( PanelToggleAffordance._radius, ), color: fill, ), child: child, ); }, child: widget.child, ), ), ); final t = widget.tooltip; if (t == null) return inkWell; return Tooltip(message: t, child: inkWell); } }