Created
May 31, 2021 03:46
-
-
Save Nash0x7E2/ee263734c4760c1244b37ae4371f58f7 to your computer and use it in GitHub Desktop.
Animating text made in Flutter. As text appear on screen, they animate between a start and ending color. Demo can be found here: https://twitter.com/Nash0x7E2/status/1399194632626520067?s=20
This file contains hidden or 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 'package:flutter/material.dart'; | |
void main() { | |
runApp(TexColDemo()); | |
} | |
class TexColDemo extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primaryColor: Colors.red, | |
), | |
home: TexColDemoBody(), | |
); | |
} | |
} | |
class TexColDemoBody extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text( | |
'Animating Text', | |
), | |
), | |
body: Center( | |
child: Padding( | |
padding: const EdgeInsets.all(28.0), | |
child: AnimatedText( | |
"A very long and interesting text used to test text animation made in Flutter :)", | |
startColor: Colors.red, | |
endColor: Colors.black, | |
textStyle: TextStyle(fontSize: 14.0), | |
animationDuration: const Duration( | |
seconds: 2, | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class AnimatedText extends StatefulWidget { | |
const AnimatedText( | |
this.text, { | |
Key? key, | |
required this.animationDuration, | |
this.colorChangeDuration: const Duration( | |
milliseconds: 600, | |
), | |
this.startColor: Colors.green, | |
this.endColor: Colors.black, | |
this.textStyle, | |
}) : super(key: key); | |
final String text; | |
final Duration animationDuration; | |
final Duration? colorChangeDuration; | |
final Color? startColor; | |
final Color? endColor; | |
final TextStyle? textStyle; | |
@override | |
_AnimatedTextState createState() => _AnimatedTextState(); | |
} | |
class _AnimatedTextState extends State<AnimatedText> | |
with SingleTickerProviderStateMixin { | |
late AnimationController _wordAnimationController; | |
@override | |
void initState() { | |
super.initState(); | |
_wordAnimationController = AnimationController( | |
vsync: this, | |
duration: widget.animationDuration, | |
); | |
_wordAnimationController.forward(); | |
} | |
@override | |
void dispose() { | |
_wordAnimationController.dispose(); | |
super.dispose(); | |
} | |
List<String> get _words => widget.text | |
.split(' ') | |
. // | |
map((word) => '$word ') | |
.toList(); | |
@override | |
Widget build(BuildContext context) { | |
final wordInterval = | |
widget.animationDuration.inMilliseconds / _words.length; | |
return AnimatedBuilder( | |
animation: _wordAnimationController, | |
builder: (BuildContext context, _) { | |
return RichText( | |
text: TextSpan( | |
children: [ | |
for (int x = 0; x < _words.length; x++) | |
if (_wordAnimationController.value >= | |
(wordInterval * x) / | |
widget.animationDuration.inMilliseconds) | |
WidgetSpan( | |
child: _AnimatedTextSpan( | |
_words[x], | |
duration: widget.colorChangeDuration, | |
endColor: widget.endColor, | |
startColor: widget.startColor, | |
style: widget.textStyle ?? | |
TextStyle( | |
fontSize: 24.0, | |
fontWeight: FontWeight.w800, | |
), | |
), | |
), | |
], | |
), | |
); | |
}, | |
); | |
} | |
} | |
class _AnimatedTextSpan extends StatefulWidget { | |
const _AnimatedTextSpan( | |
this.text, { | |
Key? key, | |
this.startColor: Colors.green, | |
this.endColor: Colors.black, | |
this.style: const TextStyle(fontSize: 12), | |
this.duration: const Duration( | |
milliseconds: 600, | |
), | |
}) : super(key: key); | |
final String text; | |
final Duration? duration; | |
final Color? startColor; | |
final Color? endColor; | |
final TextStyle? style; | |
@override | |
_AnimatedTextSpanState createState() => _AnimatedTextSpanState(); | |
} | |
class _AnimatedTextSpanState extends State<_AnimatedTextSpan> | |
with SingleTickerProviderStateMixin { | |
late AnimationController _textColorController; | |
late Animation<Color?> colorTween; | |
@override | |
void initState() { | |
super.initState(); | |
_textColorController = AnimationController( | |
vsync: this, | |
duration: widget.duration, | |
); | |
colorTween = ColorTween( | |
begin: widget.startColor, | |
end: widget.endColor, | |
).animate(_textColorController); | |
_textColorController.forward(); | |
} | |
@override | |
void dispose() { | |
_textColorController.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return AnimatedBuilder( | |
animation: _textColorController, | |
builder: (context, _) { | |
return Text( | |
widget.text, | |
style: widget.style!.copyWith(color: colorTween.value), | |
); | |
}, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment