Skip to content

Instantly share code, notes, and snippets.

@Barttje
Created February 21, 2022 07:35
Show Gist options
  • Save Barttje/9f887534d91d1bf29cb724ec62391412 to your computer and use it in GitHub Desktop.
Save Barttje/9f887534d91d1bf29cb724ec62391412 to your computer and use it in GitHub Desktop.
Example of animation with different beginning and ending
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Animation CustomPainter'),
),
body: const Center(child: ExampleWidget())),
);
}
}
class ExampleWidget extends StatefulWidget {
const ExampleWidget({Key? key}) : super(key: key);
@override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> with SingleTickerProviderStateMixin {
late Animation<double> _animation;
late Tween<double> _tween;
late AnimationController _animationController;
final List<CircleModel> _circles = [
CircleModel(const Offset(50, 100), Colors.red),
CircleModel(const Offset(150, 100), Colors.blue),
CircleModel(const Offset(250, 100), Colors.green)
];
@override
void initState() {
super.initState();
_animationController = AnimationController(duration: const Duration(milliseconds: 500), vsync: this);
_tween = Tween(begin: 50, end: 50);
_animation = _tween.animate(_animationController)
..addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
List<Widget> widgets = [];
widgets.addAll(_circles.map((e) => CircleWrapper(
center: e.center,
color: e.color,
csKey: e.key,
)));
widgets.add(CustomPaint(
painter: LinePainter(Offset(_animation.value, 150)),
));
return Listener(
onPointerDown: (PointerEvent details) {
handleClick(details);
},
child: Container(
color: Colors.grey[50],
width: 300,
height: 250,
child: Stack(
children: widgets,
),
),
);
}
handleClick(PointerEvent details) {
final circle = _circles.firstWhereOrNull((element) => isClicked(details, element.key));
if (circle != null) {
_tween.begin = _tween.end;
_animationController.reset();
_tween.end = circle.center.dx;
_animationController.forward();
}
}
bool isClicked(final PointerEvent details, final GlobalKey key) {
final result = BoxHitTestResult();
final RenderObject? circleBox = key.currentContext?.findRenderObject();
if (circleBox != null && circleBox is RenderBox) {
Offset localClick = circleBox.globalToLocal(details.position);
if (circleBox.hitTest(result, position: localClick)) {
return true;
}
}
return false;
}
}
class CircleWrapper extends StatelessWidget {
final Offset center;
final Color color;
final GlobalKey csKey;
const CircleWrapper({Key? key, required this.center, required this.color, required this.csKey}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
key: csKey,
painter: CirclePainter(center, color),
child: Container(),
);
}
}
class LinePainter extends CustomPainter {
final Offset center;
LinePainter(this.center);
@override
void paint(Canvas canvas, Size size) {
canvas.drawLine(
Offset(center.dx - 40, center.dy), Offset(center.dx + 40, center.dy), createPaintForColor(Colors.grey));
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class CirclePainter extends CustomPainter {
final Offset center;
final Color color;
CirclePainter(this.center, this.color);
@override
void paint(Canvas canvas, Size size) {
canvas.drawCircle(center, 30, createPaintForColor(color));
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
@override
bool hitTest(Offset position) {
final Path path = Path();
path.addRect(Rect.fromCircle(center: center, radius: 30));
return path.contains(position);
}
}
Paint createPaintForColor(Color color) {
return Paint()
..color = color
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 15;
}
class CircleModel {
final Offset center;
final Color color;
final GlobalKey key = GlobalKey();
CircleModel(this.center, this.color);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment