Created
April 17, 2024 07:35
-
-
Save densa/286397e55b8b67ab9a6edc6229b5819e to your computer and use it in GitHub Desktop.
typing indicator
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
/// https://docs.flutter.dev/cookbook/effects/typing-indicator | |
import 'dart:math'; | |
import 'package:core/design_system.dart'; | |
class TypingIndicator extends StatefulWidget { | |
const TypingIndicator({super.key}); | |
@override | |
State<TypingIndicator> createState() => _TypingIndicatorState(); | |
} | |
class _TypingIndicatorState extends State<TypingIndicator> | |
with TickerProviderStateMixin { | |
final List<Interval> _dotIntervals = const [ | |
Interval(0.25, 0.8), | |
Interval(0.35, 0.9), | |
Interval(0.45, 1.0), | |
]; | |
late AnimationController _repeatingController; | |
@override | |
void initState() { | |
super.initState(); | |
_repeatingController = AnimationController( | |
vsync: this, | |
duration: const Duration(milliseconds: 1500), | |
); | |
_repeatingController.repeat(); | |
} | |
@override | |
void dispose() { | |
_repeatingController.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return StatusBubble( | |
repeatingController: _repeatingController, // <-- Add this | |
dotIntervals: _dotIntervals, | |
flashingCircleDarkColor: const Color(0xFFBFBFBF), | |
flashingCircleBrightColor: const Color(0xFFE0E0E0), | |
); | |
} | |
} | |
class StatusBubble extends StatelessWidget { | |
const StatusBubble({ | |
super.key, | |
required this.repeatingController, | |
required this.dotIntervals, | |
required this.flashingCircleBrightColor, | |
required this.flashingCircleDarkColor, | |
}); | |
final AnimationController repeatingController; | |
final List<Interval> dotIntervals; | |
final Color flashingCircleDarkColor; | |
final Color flashingCircleBrightColor; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
width: 85, | |
height: 44, | |
padding: const EdgeInsets.symmetric(horizontal: 8), | |
child: Row( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: [ | |
FlashingCircle( | |
index: 0, | |
repeatingController: repeatingController, | |
dotIntervals: dotIntervals, | |
flashingCircleDarkColor: flashingCircleDarkColor, | |
flashingCircleBrightColor: flashingCircleBrightColor, | |
), | |
FlashingCircle( | |
index: 1, | |
repeatingController: repeatingController, | |
dotIntervals: dotIntervals, | |
flashingCircleDarkColor: flashingCircleDarkColor, | |
flashingCircleBrightColor: flashingCircleBrightColor, | |
), | |
FlashingCircle( | |
index: 2, | |
repeatingController: repeatingController, | |
dotIntervals: dotIntervals, | |
flashingCircleDarkColor: flashingCircleDarkColor, | |
flashingCircleBrightColor: flashingCircleBrightColor, | |
), | |
], | |
), | |
); | |
} | |
} | |
class FlashingCircle extends StatelessWidget { | |
const FlashingCircle({ | |
super.key, | |
required this.index, | |
required this.repeatingController, | |
required this.dotIntervals, | |
required this.flashingCircleBrightColor, | |
required this.flashingCircleDarkColor, | |
}); | |
final int index; | |
final AnimationController repeatingController; | |
final List<Interval> dotIntervals; | |
final Color flashingCircleDarkColor; | |
final Color flashingCircleBrightColor; | |
@override | |
Widget build(BuildContext context) { | |
return AnimatedBuilder( | |
animation: repeatingController, | |
builder: (context, child) { | |
final circleFlashPercent = dotIntervals[index].transform( | |
repeatingController.value, | |
); | |
final circleColorPercent = sin(pi * circleFlashPercent); | |
return Container( | |
width: 12, | |
height: 12, | |
decoration: BoxDecoration( | |
shape: BoxShape.circle, | |
color: Color.lerp( | |
flashingCircleDarkColor, | |
flashingCircleBrightColor, | |
circleColorPercent, | |
), | |
), | |
); | |
}, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment