Skip to content

Instantly share code, notes, and snippets.

@rrousselGit
Last active August 18, 2020 07:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rrousselGit/a48f541ffaaafe257994c6f98992fa73 to your computer and use it in GitHub Desktop.
Save rrousselGit/a48f541ffaaafe257994c6f98992fa73 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
final firstCounter = ValueNotifier(0);
final secondCounter = ValueNotifier(0);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ValueListenableBuilder<int>(
valueListenable: firstCounter,
builder: (context, value, child) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 5),
curve: Curves.easeOut,
tween: IntTween(end: value),
builder: (context, value, child) {
return Text('$value');
},
);
},
),
RaisedButton(
onPressed: () => firstCounter.value += 100,
child: Text('+'),
),
// Both counters have voluntarily a different Curve and duration
ValueListenableBuilder<int>(
valueListenable: secondCounter,
builder: (context, value, child) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 2),
curve: Curves.easeInOut,
tween: IntTween(end: value),
builder: (context, value, child) {
return Text('$value');
},
);
},
),
RaisedButton(
onPressed: () => secondCounter.value += 100,
child: Text('+'),
),
const Text('total:'),
// The total must take into account the animation of both counters
ValueListenableBuilder<int>(
valueListenable: firstCounter,
builder: (context, value, child) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 5),
curve: Curves.easeOut,
tween: IntTween(end: value),
builder: (context, value, child) {
return ValueListenableBuilder<int>(
valueListenable: secondCounter,
builder: (context, value2, child) {
return TweenAnimationBuilder<int>(
duration: const Duration(seconds: 2),
curve: Curves.easeInOut,
tween: IntTween(end: value2),
builder: (context, value2, child) {
return Text('${value + value2}');
},
);
},
);
},
);
},
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(MyApp());
}
final firstCounter = ValueNotifier(0);
final secondCounter = ValueNotifier(0);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends HookWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
HookBuilder(
builder: (context) {
final value = useFirstCounter();
return Text('$value');
},
),
RaisedButton(
onPressed: () => firstCounter.value += 100,
child: Text('+'),
),
HookBuilder(
builder: (context) {
final value = useSecondCounter();
return Text('$value');
},
),
RaisedButton(
onPressed: () => secondCounter.value += 100,
child: Text('+'),
),
const Text('total:'),
// The total must take into account the animation of both counters
HookBuilder(
builder: (context) {
final value = useFirstCounter();
final value2 = useSecondCounter();
return Text('${value + value2}');
},
),
],
),
),
);
}
}
// Both animations voluntarily have a different Duration/Curve
int useFirstCounter() {
return useAnimatedInt(
useValueListenable(firstCounter),
duration: const Duration(seconds: 5),
curve: Curves.easeOut,
);
}
int useSecondCounter() {
return useAnimatedInt(
useValueListenable(secondCounter),
duration: const Duration(seconds: 2),
curve: Curves.easeInOut,
);
}
int useAnimatedInt(
int value, {
@required Duration duration,
Curve curve = Curves.linear,
}) {
final controller = useAnimationController(duration: duration);
return useAnimation(use(_AnimatedIntHook(value, curve, controller)));
}
class _AnimatedIntHook extends Hook<Animation<int>> {
_AnimatedIntHook(this.value, this.curve, this.controller);
final int value;
final Curve curve;
final AnimationController controller;
@override
_AnimatedIntState createState() {
return _AnimatedIntState();
}
}
class _AnimatedIntState extends HookState<Animation<int>, _AnimatedIntHook> {
Animation<int> animation;
@override
void initHook() {
animation = AlwaysStoppedAnimation(hook.value);
}
@override
void didUpdateHook(_AnimatedIntHook oldHook) {
if (oldHook.value != hook.value) {
final tween = IntTween(begin: animation.value, end: hook.value);
animation = hook.controller.drive(
tween.chain(CurveTween(curve: hook.curve)),
);
hook.controller.forward(from: 0);
}
}
@override
Animation<int> build(BuildContext context) => animation;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment