Skip to content

Instantly share code, notes, and snippets.

@Kurogoma4D
Last active October 30, 2022 06:19
Show Gist options
  • Save Kurogoma4D/9146fec775c5e052eb72e6f7474a904d to your computer and use it in GitHub Desktop.
Save Kurogoma4D/9146fec775c5e052eb72e6f7474a904d to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
typedef ValueTransitionBuilder<T> = Widget Function(
BuildContext context,
T value,
Widget? child,
);
class AutoTransition<T> extends StatefulWidget {
const AutoTransition({
super.key,
required this.property,
required this.duration,
this.curve = Curves.linear,
required this.builder,
this.child,
});
final T property;
final Duration duration;
final Curve curve;
final ValueTransitionBuilder<T> builder;
final Widget? child;
@override
State<AutoTransition<T>> createState() => _AutoTransitionState();
}
class _AutoTransitionState<T> extends State<AutoTransition<T>>
with SingleTickerProviderStateMixin {
late final _controller =
AnimationController(vsync: this, duration: widget.duration);
Animation<T>? _animation;
Animation<T> get _defaultAnimation =>
Tween(begin: widget.property, end: widget.property).animate(_controller);
@override
void didUpdateWidget(covariant AutoTransition<T> oldWidget) {
super.didUpdateWidget(oldWidget);
final curved = CurvedAnimation(
parent: _controller,
curve: widget.curve,
);
_animation =
Tween(begin: oldWidget.property, end: widget.property).animate(curved);
_controller.forward(from: 0);
}
@override
Widget build(BuildContext context) {
final animation = _animation ?? _defaultAnimation;
return AnimatedBuilder(
animation: animation,
builder: (context, child) =>
widget.builder(context, animation.value, child),
child: widget.child,
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double someValue = 0.0;
void _setValue() {
setState(() {
someValue = someValue == 0.0 ? 1.0 : 0.0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Hello'),
),
body: Center(
child: GestureDetector(
onTap: _setValue,
child: AutoTransition<double>(
duration: const Duration(milliseconds: 300),
property: someValue,
builder: (context, value, _) => Container(
width: 100,
height: 100,
color: Colors.amber,
child: Center(child: Text(value.toStringAsFixed(3))),
),
),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
typedef ValueTransitionBuilder<T> = Widget Function(
BuildContext context,
T value,
Widget? child,
);
class AutoTransition<T> extends StatefulWidget {
const AutoTransition({
super.key,
required this.property,
required this.duration,
this.curve = Curves.linear,
required this.builder,
this.child,
});
final T property;
final Duration duration;
final Curve curve;
final ValueTransitionBuilder<T> builder;
final Widget? child;
@override
State<AutoTransition<T>> createState() => _AutoTransitionState();
}
class _AutoTransitionState<T, TTween extends Tween<T?>>
extends State<AutoTransition<T>> with SingleTickerProviderStateMixin {
late final _controller =
AnimationController(vsync: this, duration: widget.duration);
Animation<T?>? _animation;
Animation<T?> get _defaultAnimation =>
_generateTween(widget.property, widget.property).animate(_controller);
@override
void didUpdateWidget(covariant AutoTransition<T> oldWidget) {
super.didUpdateWidget(oldWidget);
final curved = CurvedAnimation(
parent: _controller,
curve: widget.curve,
);
_animation =
_generateTween(oldWidget.property, widget.property).animate(curved);
_controller.forward(from: 0);
}
@override
Widget build(BuildContext context) {
final animation = _animation ?? _defaultAnimation;
return AnimatedBuilder(
animation: animation,
builder: (context, child) =>
widget.builder(context, animation.value ?? widget.property, child),
child: widget.child,
);
}
TTween _generateTween(T begin, T end) {
final result = () {
if (begin is Color) {
return ColorTween(begin: begin, end: end as Color);
}
if (begin is Size) {
return SizeTween(begin: begin, end: end as Size);
}
return Tween<T>(begin: begin, end: end);
}();
return result as TTween;
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Size someSize = const Size(100, 100);
void _setValue() {
setState(() {
someSize += const Offset(10, 10);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Hello'),
),
body: Center(
child: GestureDetector(
onTap: _setValue,
child: AutoTransition<Size>(
duration: const Duration(seconds: 1),
property: someSize,
builder: (context, value, _) => Container(
width: value.width,
height: value.height,
color: Colors.blue,
),
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment