87 lines
2.1 KiB
Dart
87 lines
2.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:haptic_feedback/haptic_feedback.dart';
|
|
|
|
class BouncyTap extends StatefulWidget {
|
|
final Widget child;
|
|
final VoidCallback? onPressed;
|
|
final double scaleDown;
|
|
final Duration duration;
|
|
final bool enableHaptic;
|
|
final HitTestBehavior behavior;
|
|
|
|
const BouncyTap({
|
|
super.key,
|
|
required this.child,
|
|
this.onPressed,
|
|
this.scaleDown = 0.95,
|
|
this.duration = const Duration(milliseconds: 100),
|
|
this.enableHaptic = true,
|
|
this.behavior = HitTestBehavior.opaque,
|
|
});
|
|
|
|
@override
|
|
State<BouncyTap> createState() => _BouncyTapState();
|
|
}
|
|
|
|
class _BouncyTapState extends State<BouncyTap> with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
late Animation<double> _scaleAnimation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(vsync: this, duration: widget.duration);
|
|
_scaleAnimation = Tween<double>(begin: 1.0, end: widget.scaleDown).animate(
|
|
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _onTapDown(TapDownDetails details) {
|
|
if (widget.onPressed != null) {
|
|
if (widget.enableHaptic) {
|
|
Haptics.vibrate(HapticsType.light);
|
|
}
|
|
_controller.forward();
|
|
}
|
|
}
|
|
|
|
void _onTapUp(TapUpDetails details) {
|
|
if (widget.onPressed != null) {
|
|
_controller.reverse();
|
|
widget.onPressed!();
|
|
}
|
|
}
|
|
|
|
void _onTapCancel() {
|
|
if (widget.onPressed != null) {
|
|
_controller.reverse();
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
behavior: widget.behavior,
|
|
onTapDown: _onTapDown,
|
|
onTapUp: _onTapUp,
|
|
onTapCancel: _onTapCancel,
|
|
child: AnimatedBuilder(
|
|
animation: _scaleAnimation,
|
|
builder: (context, child) {
|
|
return Transform.scale(
|
|
scale: _scaleAnimation.value,
|
|
alignment: Alignment.center,
|
|
child: widget.child,
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|