Skip to content

Instantly share code, notes, and snippets.

@rohan20
Last active February 24, 2024 00:20
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rohan20/b1a15c09bbb8d18c4caa9e8c41a108c0 to your computer and use it in GitHub Desktop.
Save rohan20/b1a15c09bbb8d18c4caa9e8c41a108c0 to your computer and use it in GitHub Desktop.
Flutter button tap to shrink animation effect
// Interactive Demo: https://dartpad.dev/b1a15c09bbb8d18c4caa9e8c41a108c0?null_safety=true
// GIF Demo: See first comment below
import 'package:flutter/material.dart';
void main() {
runApp(DemoApp());
}
class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
height: 48,
width: 200,
child: CoreButton(text: "Tap Me", onTap: () {}),
),
),
),
);
}
}
class CoreButton extends StatefulWidget {
final String text;
final VoidCallback? onTap;
const CoreButton({required this.text, this.onTap});
@override
_CoreButtonState createState() => _CoreButtonState();
}
class _CoreButtonState extends State<CoreButton>
with SingleTickerProviderStateMixin {
static const clickAnimationDurationMillis = 100;
double _scaleTransformValue = 1;
// needed for the "click" tap effect
late final AnimationController animationController;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: clickAnimationDurationMillis),
lowerBound: 0.0,
upperBound: 0.05,
)..addListener(() {
setState(() => _scaleTransformValue = 1 - animationController.value);
});
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
void _shrinkButtonSize() {
animationController.forward();
}
void _restoreButtonSize() {
Future.delayed(
const Duration(milliseconds: clickAnimationDurationMillis),
() => animationController.reverse(),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
widget.onTap?.call();
_shrinkButtonSize();
_restoreButtonSize();
},
onTapDown: (_) => _shrinkButtonSize(),
onTapCancel: _restoreButtonSize,
child: Transform.scale(
scale: _scaleTransformValue,
child: Container(
decoration: BoxDecoration(
color: const Color(0xFF37003C),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
widget.text,
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
),
),
),
);
}
}
@rohan20
Copy link
Author

rohan20 commented Jun 5, 2021

flutter-button-tap-to-shrink

@rohan20
Copy link
Author

rohan20 commented Jun 6, 2021

Make it better:

      onTap: () {
        // UX delight: Adding this delay let's the user see the tap
        // animation before the tap action is performed instead of instantly
        // performing the action. This is great in cases where the tap action
        // triggers navigation. If we remove this delay, the app would navigate
        // instantly and hence the user wouldn't be able to see the button
        // animation in action.
        Future.delayed(
          const Duration(milliseconds: clickAnimationDurationMillis * 2),
          () => widget.onTap?.call(),
        );
        _shrinkButtonSize();
        _restoreButtonSize();
      },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment