Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active April 16, 2020 16:07
Show Gist options
  • Save slightfoot/b37367e9666dc19378924713564cc4b7 to your computer and use it in GitHub Desktop.
Save slightfoot/b37367e9666dc19378924713564cc4b7 to your computer and use it in GitHub Desktop.
Animated Button: Animates is size and content after being pressed - by Simon Lightfoot
// MIT License
//
// Copyright (c) 2020 Simon Lightfoot
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import 'package:flutter/material.dart';
void main() => runApp(ExampleApp());
class ExampleApp extends StatefulWidget {
@override
_ExampleAppState createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.indigo,
accentColor: Colors.pinkAccent,
),
home: Scaffold(
appBar: AppBar(
title: Text('Animated Button Example'),
),
body: Center(
child: Transform.scale(
scale: 3.0,
child: AnimatedButton(
text: 'Press Me',
icon: Icons.check,
textTheme: ButtonTextTheme.accent,
onPressed: () {
print('pressed');
},
),
),
),
),
);
}
}
class AnimatedButton extends StatefulWidget {
const AnimatedButton({
Key key,
@required this.text,
@required this.icon,
this.onPressed,
this.pauseDuration = const Duration(milliseconds: 1000),
this.animDuration = const Duration(milliseconds: 300),
this.textTheme = ButtonTextTheme.normal,
}) : super(key: key);
final String text;
final IconData icon;
final VoidCallback onPressed;
final Duration pauseDuration;
final Duration animDuration;
final ButtonTextTheme textTheme;
@override
_AnimatedButtonState createState() => _AnimatedButtonState();
}
class _AnimatedButtonState extends State<AnimatedButton>
with TickerProviderStateMixin {
int _index = 0;
Future<void> _onButtonPressed() async {
if (_index == 1) {
return;
}
setState(() => _index = 1);
await Future.delayed(
widget.pauseDuration.compareTo(widget.animDuration) >= 0
? widget.pauseDuration
: widget.animDuration);
widget.onPressed?.call();
if (mounted) {
setState(() => _index = 0);
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Color color;
TextTheme textTheme;
IconThemeData iconTheme;
switch (widget.textTheme) {
case ButtonTextTheme.accent:
color = theme.accentColor;
textTheme = theme.accentTextTheme;
iconTheme = theme.accentIconTheme;
break;
case ButtonTextTheme.primary:
color = theme.primaryColor;
textTheme = theme.primaryTextTheme;
iconTheme = theme.primaryIconTheme;
break;
default:
break;
}
return MaterialButton(
color: color,
shape: _index == 0
? RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0))
: StadiumBorder(),
animationDuration: widget.animDuration,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: EdgeInsets.zero,
minWidth: 0.0,
onPressed: widget.onPressed != null ? _onButtonPressed : null,
child: DefaultTextStyle(
style: textTheme.button,
child: IconTheme(
data: iconTheme,
child: AnimatedSize(
duration: widget.animDuration,
vsync: this,
child: AnimatedSwitcher(
duration: widget.animDuration,
switchInCurve: Interval(0.5, 1.0, curve: Curves.easeIn),
switchOutCurve: Interval(0.0, 0.5, curve: Curves.easeOut),
child: _index == 0
? Padding(
key: Key('text'),
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
child: Text(widget.text),
)
: Padding(
key: Key('icon'),
padding: const EdgeInsets.all(8.0),
child: Icon(widget.icon),
),
),
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment