pressable.dart 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/services.dart';
  3. /// A lightweight press-scale wrapper used instead of InkWell for the large
  4. /// dashboard tiles. It keeps touch feedback cheap on older devices.
  5. class Pressable extends StatefulWidget {
  6. const Pressable({
  7. super.key,
  8. required this.child,
  9. this.onTap,
  10. this.onLongPress,
  11. this.semanticLabel,
  12. this.pressedScale = 0.965,
  13. this.borderRadius = BorderRadius.zero,
  14. });
  15. final Widget child;
  16. final VoidCallback? onTap;
  17. final VoidCallback? onLongPress;
  18. final String? semanticLabel;
  19. final double pressedScale;
  20. final BorderRadius borderRadius;
  21. @override
  22. State<Pressable> createState() => _PressableState();
  23. }
  24. class _PressableState extends State<Pressable> {
  25. bool _pressed = false;
  26. void _setPressed(bool pressed) {
  27. if (!mounted || _pressed == pressed) return;
  28. setState(() => _pressed = pressed);
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. final canInteract = widget.onTap != null || widget.onLongPress != null;
  33. return Semantics(
  34. button: canInteract,
  35. label: widget.semanticLabel,
  36. child: GestureDetector(
  37. behavior: HitTestBehavior.opaque,
  38. onTapDown: canInteract ? (_) => _setPressed(true) : null,
  39. onTapUp: canInteract ? (_) => _setPressed(false) : null,
  40. onTapCancel: canInteract ? () => _setPressed(false) : null,
  41. onTap: widget.onTap,
  42. onLongPress: widget.onLongPress == null
  43. ? null
  44. : () {
  45. HapticFeedback.mediumImpact();
  46. widget.onLongPress!();
  47. },
  48. child: AnimatedScale(
  49. scale: _pressed ? widget.pressedScale : 1,
  50. duration: const Duration(milliseconds: 110),
  51. curve: Curves.easeOutCubic,
  52. child: widget.child,
  53. ),
  54. ),
  55. );
  56. }
  57. }