mix
mix copied to clipboard
Animations as attribute
Package version
1.0.0-beta.1
Flutter version
Flutter 3.16.8 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 67457e669f (10 days ago) • 2024-01-16 16:22:29 -0800
Engine • revision 6e2ea58a5c
Tools • Dart 3.2.5 • DevTools 2.28.5
Steps to reproduce
I tried to create a animation that changes the background color to another over a specific duration when the user hovers the widget. To do this, I used an AnimatedBox
as shown in the code below:
Pressable(
child: AnimatedBox(
duration: const Duration(milliseconds: 300),
style: Style(
height(50),
width(50),
backgroundColor.red(),
onHover(
backgroundColor.blue(),
),
),
),
)
Perfect! This code works really well. to make this animation avaliable to other widgets. I developed an attribute to handle it using WidgetDecorator
, as shown below::
class ColorTransitionOnHoverDecorator
extends WidgetDecorator<ColorTransitionOnHoverDecorator> {
final Color initialColor;
final Color finalColor;
final Duration duration;
const ColorTransitionOnHoverDecorator(
this.initialColor,
this.finalColor, {
required this.duration,
super.key,
});
@override
ColorTransitionOnHoverDecorator lerp(VisibilityDecorator? other, double t) {
return ColorTransitionOnHoverDecorator(initialColor, finalColor,
duration: Duration.zero);
}
@override
get props => [initialColor];
@override
Widget build(mix, child) => AnimatedBox(
duration: duration,
style: Style(
box.color(initialColor),
onHover(
box.color(finalColor),
),
),
child: child,
);
}
class ColorTransitionOnHoverUtility<T extends StyleAttribute>
extends MixUtility<T, ColorTransitionOnHoverDecorator> {
const ColorTransitionOnHoverUtility(super.builder);
T call(
Color initialColor,
Color finalColor, {
required Duration duration,
Key? key,
}) =>
builder(ColorTransitionOnHoverDecorator(
initialColor,
finalColor,
duration: duration,
key: key,
));
}
final colorTransitionOnHover = ColorTransitionOnHoverUtility((d) => d);
Therefore, I replace the AnimatedBox
with the new attribute colorTransitionOnHover
:
Pressable(
child: Box(
style: Style(
height(50),
width(50),
colorTransitionOnHover(
Colors.red,
Colors.blue,
duration: const Duration(milliseconds: 300),
),
),
),
)
It's also work well! However, when I applied the same attribute colorTransitionOnHover
to an HBox, it didn't work. The HBox didn't receive any Flex attributes.
Pressable(
child: HBox(
style: Style(
flex.mainAxisSize.min(),
flex.crossAxisAlignment.center(),
flex.mainAxisAlignment.end(),
padding(10),
colorTransitionOnHover(
Colors.blueAccent,
Colors.redAccent,
duration: const Duration(milliseconds: 300),
),
),
children: [
Box(
style: Style(
height(50),
width(50),
backgroundColor.black(),
),
),
Box(
style: Style(
height(50),
width(50),
backgroundColor.white(),
),
)
],
),
);
Expected results
https://github.com/conceptadev/mix/assets/62367544/d8907e4d-3e60-4f7d-bd5b-e05e92e34483
Actual results
https://github.com/conceptadev/mix/assets/62367544/1f6409bc-f0b8-4bc9-bee3-1a955072b11a
Code sample
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: WidgetAnimatedWithAttribute(),
),
),
);
}
}
class WidgetAnimatedWithoutAttribute extends StatelessWidget {
const WidgetAnimatedWithoutAttribute({
super.key,
});
@override
Widget build(BuildContext context) {
return Pressable(
child: AnimatedBox(
duration: const Duration(milliseconds: 300),
style: Style(
box.color(Colors.blueAccent),
onHover(
box.color(Colors.redAccent),
),
),
child: HBox(
style: Style(
flex.mainAxisSize.min(),
flex.crossAxisAlignment.center(),
flex.mainAxisAlignment.end(),
padding(10),
),
children: [
Box(
style: Style(
height(50),
width(50),
backgroundColor.black(),
),
),
Box(
style: Style(
height(50),
width(50),
backgroundColor.white(),
),
)
],
// duration: const Duration(milliseconds: 300),
),
),
);
}
}
class WidgetAnimatedWithAttribute extends StatelessWidget {
const WidgetAnimatedWithAttribute({
super.key,
});
@override
Widget build(BuildContext context) {
return Pressable(
child: HBox(
style: Style(
flex.mainAxisSize.min(),
flex.crossAxisAlignment.center(),
flex.mainAxisAlignment.end(),
padding(10),
colorTransitionOnHover(
Colors.blueAccent,
Colors.redAccent,
duration: const Duration(milliseconds: 300),
),
),
children: [
Box(
style: Style(
height(50),
width(50),
backgroundColor.black(),
),
),
Box(
style: Style(
height(50),
width(50),
backgroundColor.white(),
),
)
],
// duration: const Duration(milliseconds: 300),
),
);
}
}
class ColorTransitionOnHoverDecorator
extends WidgetDecorator<ColorTransitionOnHoverDecorator> {
final Color initialColor;
final Color finalColor;
final Duration duration;
const ColorTransitionOnHoverDecorator(
this.initialColor,
this.finalColor, {
required this.duration,
super.key,
});
@override
ColorTransitionOnHoverDecorator lerp(VisibilityDecorator? other, double t) {
return ColorTransitionOnHoverDecorator(initialColor, finalColor,
duration: Duration.zero);
}
@override
get props => [initialColor];
@override
Widget build(mix, child) => AnimatedBox(
duration: duration,
style: Style(
box.color(initialColor),
onHover(
box.color(finalColor),
),
),
child: child,
);
}
class ColorTransitionOnHoverUtility<T extends StyleAttribute>
extends MixUtility<T, ColorTransitionOnHoverDecorator> {
const ColorTransitionOnHoverUtility(super.builder);
T call(
Color initialColor,
Color finalColor, {
required Duration duration,
Key? key,
}) =>
builder(ColorTransitionOnHoverDecorator(
initialColor,
finalColor,
duration: duration,
key: key,
));
}
final colorTransitionOnHover = ColorTransitionOnHoverUtility((d) => d);