Created
April 10, 2023 16:43
-
-
Save damywise/22b5e3ba9f1ee76e6a6b4fa078660e60 to your computer and use it in GitHub Desktop.
fl_chart reveal animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math'; | |
import 'package:fl_chart/fl_chart.dart'; | |
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
// | |
primarySwatch: Colors.blue, | |
), | |
home: const MyHomePage(title: 'Flutter Demo Home Page'), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
const MyHomePage({super.key, required this.title}); | |
final String title; | |
@override | |
State<MyHomePage> createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
int _counter = 0; | |
double targetValue = 0; | |
bool showDot1 = false; | |
bool showDot2 = false; | |
final showDotDuration = const Duration(milliseconds: 500); | |
final duration = const Duration(milliseconds: 1000); | |
final duration2 = const Duration(milliseconds: 700); | |
void _incrementCounter() { | |
setState(() { | |
_counter++; | |
if (showDot1) { | |
showDot2 = false; | |
targetValue = targetValue == 0 ? 350 : 0; | |
Future.delayed(duration, () => setState(() => showDot1 = false),); | |
} else { | |
showDot1 = true; | |
Future.delayed(showDotDuration, () => setState(() => targetValue = targetValue == 0 ? 350 : 0)); | |
Future.delayed(duration, () => setState(() => showDot2 = true),); | |
} | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(widget.title), | |
), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
SizedBox( | |
width: 300, | |
height: 300, | |
child: Stack( | |
children: [ | |
LineChart( | |
LineChartData( | |
maxX: 10, | |
maxY: 10, | |
minX: 0, | |
minY: 0, | |
titlesData: FlTitlesData( | |
show: true, | |
topTitles: AxisTitles(), | |
rightTitles: AxisTitles(), | |
), | |
gridData: FlGridData(show: false), | |
borderData: FlBorderData(show: false), | |
), | |
), | |
TweenAnimationBuilder( | |
tween: Tween<double>(begin: 0, end: targetValue), | |
duration: duration, | |
builder: (context, value, child) { | |
return ShaderMask( | |
blendMode: BlendMode.dstIn, | |
shaderCallback: (Rect bounds) { | |
return const LinearGradient( | |
begin: Alignment.topCenter, | |
end: Alignment.bottomCenter, | |
stops: [1, 1], | |
colors: [Colors.black, Colors.transparent]) | |
.createShader( | |
Rect.fromLTWH( | |
35, 300 - 75 - (6 / 10 * 300), value, value), | |
); | |
}, | |
child: ShaderMask( | |
blendMode: BlendMode.dstIn, | |
shaderCallback: (Rect bounds) { | |
return const LinearGradient( | |
begin: Alignment.centerLeft, | |
end: Alignment.centerRight, | |
stops: [ | |
1, | |
1 | |
], | |
colors: [ | |
Colors.black, | |
Colors.transparent | |
]).createShader( | |
Rect.fromLTWH( | |
35, 300 - 75 - (6 / 10 * 300), value, value), | |
); | |
}, | |
child: LineChart( | |
LineChartData( | |
maxX: 10, | |
maxY: 10, | |
minX: 0, | |
minY: 0, | |
titlesData: FlTitlesData( | |
show: true, | |
topTitles: AxisTitles(), | |
rightTitles: AxisTitles(), | |
), | |
rangeAnnotations: RangeAnnotations( | |
horizontalRangeAnnotations: [], | |
verticalRangeAnnotations: []), | |
gridData: FlGridData(show: false), | |
borderData: FlBorderData(show: false), | |
lineBarsData: [ | |
LineChartBarData( | |
color: Colors.red, | |
barWidth: 8, | |
isStrokeCapRound: true, | |
dotData: FlDotData(show: false), | |
spots: [ | |
const FlSpot(0, 8), | |
const FlSpot(1, 7), | |
const FlSpot(3, 5), | |
const FlSpot(10, 3) | |
], | |
isCurved: true, | |
belowBarData: BarAreaData( | |
show: true, color: Colors.redAccent), | |
), | |
], | |
clipData: FlClipData.all(), | |
), | |
), | |
), | |
); | |
}), | |
TweenAnimationBuilder( | |
tween: Tween<double>(begin: 0, end: targetValue), | |
duration: duration2, | |
builder: (context, value, child) { | |
return ShaderMask( | |
blendMode: BlendMode.dstIn, | |
shaderCallback: (Rect bounds) { | |
return const LinearGradient( | |
begin: Alignment.topCenter, | |
end: Alignment.bottomCenter, | |
stops: [1, 1], | |
colors: [Colors.black, Colors.transparent]) | |
.createShader( | |
Rect.fromLTWH( | |
35, 300 - 75 - (6 / 10 * 300), value, value), | |
); | |
}, | |
child: ShaderMask( | |
blendMode: BlendMode.dstIn, | |
shaderCallback: (Rect bounds) { | |
return const LinearGradient( | |
begin: Alignment.centerLeft, | |
end: Alignment.centerRight, | |
stops: [1, 1], | |
colors: [Colors.black, Colors.transparent]) | |
.createShader( | |
Rect.fromLTWH( | |
35, 300 - 75 - (6 / 10 * 300), value, value), | |
); | |
}, | |
child: LineChart( | |
LineChartData( | |
maxX: 10, | |
maxY: 10, | |
minX: 0, | |
minY: 0, | |
titlesData: FlTitlesData( | |
show: true, | |
topTitles: AxisTitles(), | |
rightTitles: AxisTitles(), | |
), | |
rangeAnnotations: RangeAnnotations( | |
horizontalRangeAnnotations: [], | |
verticalRangeAnnotations: []), | |
gridData: FlGridData(show: false), | |
borderData: FlBorderData(show: false), | |
lineBarsData: [ | |
LineChartBarData( | |
barWidth: 8, | |
isStrokeCapRound: true, | |
dotData: FlDotData(show: false), | |
spots: [ | |
const FlSpot(0, 8), | |
const FlSpot(3, 4), | |
const FlSpot(5, 3), | |
const FlSpot(10, 1) | |
], | |
isCurved: true, | |
belowBarData: BarAreaData( | |
show: true, color: Colors.blueGrey), | |
), | |
], | |
clipData: FlClipData.all(), | |
), | |
), | |
), | |
); | |
}, | |
), | |
AnimatedPositioned( | |
duration: const Duration(milliseconds: 100), | |
top: 2 / 10 * 300, | |
left: 40, | |
child: Transform.translate( | |
offset: const Offset(0, -4 - (2 / 10 * 34)), | |
child: Stack( | |
children: [ | |
AnimatedScale( | |
scale: !showDot1 ? 0.0 : 2.0, | |
duration: showDotDuration, | |
curve: Curves.easeInOutBack, | |
child: const CircleAvatar( | |
radius: 5, | |
), | |
), | |
AnimatedScale( | |
scale: !showDot1 ? 0.0 : 1.0, | |
duration: const Duration(milliseconds: 500), | |
curve: Curves.easeInOutBack, | |
child: const CircleAvatar( | |
radius: 5, | |
backgroundColor: Colors.lightBlueAccent, | |
), | |
), | |
], | |
), | |
), | |
), | |
AnimatedPositioned( | |
duration: const Duration(milliseconds: 100), | |
top: 9 / 10 * 300, | |
left: 10 / 10 * 300 - 10, | |
child: Transform.translate( | |
offset: const Offset(0, -4 - (9 / 10 * 34)), | |
child: Stack( | |
children: [ | |
AnimatedScale( | |
scale: !showDot2 ? 0.0 : 2.0, | |
duration: showDotDuration, | |
curve: Curves.easeInOutBack, | |
child: const CircleAvatar( | |
radius: 5, | |
), | |
), | |
AnimatedScale( | |
scale: !showDot2 ? 0.0 : 1.0, | |
duration: const Duration(milliseconds: 500), | |
curve: Curves.easeInOutBack, | |
child: const CircleAvatar( | |
radius: 5, | |
backgroundColor: Colors.lightBlueAccent, | |
), | |
), | |
], | |
), | |
), | |
), | |
], | |
), | |
), | |
const Text( | |
'You have pushed the button this many times:', | |
), | |
Text( | |
'$_counter', | |
style: Theme.of(context).textTheme.headlineMedium, | |
), | |
], | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _incrementCounter, | |
tooltip: 'Increment', | |
child: const Icon(Icons.add), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment