I am trying to build a widget that can be shown or hidden, and when it is shown, will have is displayed text 'grow' over a certain duration. I've based it mostly on the typing indicator example.
The idea is to have the widget in e.g. a form with state and provide some pretty user feedback in certain circumstances, such as during and after a validation REST call.
I can't quite figure out how to 'plug in' the AnimationController, in order to grow substring of the input string to display.
i.e. in the form the widget will be something like
AnimatedText(
textContent: stringFeedback,
doShowMe: haveFeedback,
),
... and in my async input processing method i have a setState(() => haveFeedback = true); and a false etc.
I imagine I need to call a something like the updateText() method below from somewhere somehow linked the the value of the AnimationControler _appearanceController but how to have that be a loop escapes me - still being new to the flutter/Dart and for that matter OOP paradigm.
What I have so far is:
import 'package:flutter/material.dart';
import 'dart:developer' as developer;
class AnimatedText extends StatefulWidget {
const AnimatedText({
Key? key,
this.doShowMe = false,
this.textContent = '',
}) : super(key: key);
final bool doShowMe;
final String textContent;
@override
State<AnimatedText> createState() => _AnimatedTextState();
}
class _AnimatedTextState extends State<AnimatedText>
with SingleTickerProviderStateMixin {
late AnimationController _appearanceController;
late String displayText;
@override
void initState() {
super.initState();
developer.log('_AnimatedTextState init ');
_appearanceController = AnimationController(vsync: this);
displayText = '';
if (widget.doShowMe) {
_doShowMe();
}
}
@override
void didUpdateWidget(AnimatedText oldWidget) {
super.didUpdateWidget(oldWidget);
developer.log('_AnimatedTextState didUpdateWidget');
if (widget.doShowMe != oldWidget.doShowMe) {
if (widget.doShowMe) {
developer.log('_AnimatedTextState didUpdateWidget show');
_doShowMe();
} else {
developer.log('_AnimatedTextState didUpdateWidget hide');
_hideIndicator();
}
}
}
@override
void dispose() {
developer.log('_AnimatedTextState dispose');
_appearanceController.dispose();
displayText = '';
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _appearanceController,
builder: (context, child) {
return Container(
child: Text(displayText),
);
});
}
void updateText() {
//something like...
String payload = widget.textContent;
if (displayText != payload) {
int numCharsToShow =
(_appearanceController.value * widget.textContent.length).ceil();
displayText = payload.substring(0, numCharsToShow);
developer.log('updated displayText up to $numCharsToShow');
}
}
void _doShowMe() {
_appearanceController
..duration = const Duration(milliseconds: 750)
..forward();
}
void _hideIndicator() {
_appearanceController
..duration = const Duration(milliseconds: 150)
..reverse();
}
}
Any help much appreciated.
You can use the addListener method to execute some code whenever the value of the
AnimationControlerchanges.Between that and the didUpdateWidget method one should be able to deal with most scenarios I think.
In the below code the widget will grow with its payload text appearing as if typed character by character.
When the Boolean variable controling whether it should be shown or hidden changes it will shrink or grow.
If the payload variable changes while the text is being shown, the animation is reset and starts over.
Usage example: