Add scale animation to category card (#90)

This commit is contained in:
Tommy Chow 2022-06-27 11:16:47 -04:00
parent d349c98789
commit d9a76123f6

View file

@ -9,7 +9,7 @@ import 'package:frosty/widgets/loading_indicator.dart';
import 'package:provider/provider.dart';
/// A tappable card widget that displays a category's box art and name.
class CategoryCard extends StatelessWidget {
class CategoryCard extends StatefulWidget {
final CategoryTwitch category;
final int width;
final int height;
@ -21,52 +21,91 @@ class CategoryCard extends StatelessWidget {
required this.height,
}) : super(key: key);
@override
State<CategoryCard> createState() => _CategoryCardState();
}
class _CategoryCardState extends State<CategoryCard> with SingleTickerProviderStateMixin {
late final _animationController = AnimationController(
vsync: this,
upperBound: 0.05,
);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CategoryStreams(
listStore: ListStore(
twitchApi: context.read<TwitchApi>(),
authStore: context.read<AuthStore>(),
listType: ListType.category,
categoryInfo: category,
return AnimatedBuilder(
animation: _animationController,
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CategoryStreams(
listStore: ListStore(
twitchApi: context.read<TwitchApi>(),
authStore: context.read<AuthStore>(),
listType: ListType.category,
categoryInfo: widget.category,
),
),
),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Column(
children: [
Expanded(
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
child: AspectRatio(
aspectRatio: 3 / 4,
child: CachedNetworkImage(
imageUrl: category.boxArtUrl.replaceRange(category.boxArtUrl.lastIndexOf('-') + 1, null, '${width}x$height.jpg'),
placeholder: (context, url) => const LoadingIndicator(),
onTapDown: (_) => _animationController.animateTo(
_animationController.upperBound,
curve: Curves.easeOutBack,
duration: const Duration(milliseconds: 200),
),
onTapUp: (_) => _animationController.animateTo(
_animationController.lowerBound,
curve: Curves.easeOutBack,
duration: const Duration(milliseconds: 300),
),
onTapCancel: () => _animationController.animateTo(
_animationController.lowerBound,
curve: Curves.easeOutBack,
duration: const Duration(milliseconds: 300),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Column(
children: [
Expanded(
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
child: AspectRatio(
aspectRatio: 3 / 4,
child: CachedNetworkImage(
imageUrl: widget.category.boxArtUrl
.replaceRange(widget.category.boxArtUrl.lastIndexOf('-') + 1, null, '${widget.width}x${widget.height}.jpg'),
placeholder: (context, url) => const LoadingIndicator(),
),
),
),
),
),
const SizedBox(height: 5.0),
Tooltip(
message: category.name,
preferBelow: false,
padding: const EdgeInsets.all(10.0),
child: Text(
category.name,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
const SizedBox(height: 5.0),
Tooltip(
message: widget.category.name,
preferBelow: false,
padding: const EdgeInsets.all(10.0),
child: Text(
widget.category.name,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
),
),
),
],
],
),
),
),
builder: (context, child) => Transform.scale(
scale: 1 - _animationController.value,
child: child,
),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}