Add scale animation to category card (#90)
This commit is contained in:
parent
d349c98789
commit
d9a76123f6
1 changed files with 75 additions and 36 deletions
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue