Voice Assistant
Loading preview
Starting the Flutter app
A Flutter voice assistant UI with an animated waveform, a listening state, and a transcript.
import 'dart:math';
import 'package:flutter/material.dart';
class VoiceAssistant extends StatefulWidget {
const VoiceAssistant({super.key});
@override
State<VoiceAssistant> createState() => _VoiceAssistantState();
}
class _VoiceAssistantState extends State<VoiceAssistant>
with SingleTickerProviderStateMixin {
late final AnimationController _c =
AnimationController(vsync: this, duration: const Duration(milliseconds: 700))
..repeat(reverse: true);
bool _listening = true;
@override
void dispose() {
_c.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scheme = theme.colorScheme;
return Scaffold(
appBar: AppBar(title: const Text('Voice Assistant')),
body: Padding(
padding: const EdgeInsets.all(28),
child: Column(
children: [
const Spacer(),
Text(_listening ? 'Listening…' : 'Tap the mic to speak',
style: theme.textTheme.titleMedium),
const SizedBox(height: 32),
SizedBox(
height: 80,
child: AnimatedBuilder(
animation: _c,
builder: (context, _) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: List.generate(24, (i) {
final base = sin((i / 24) * pi);
final h = _listening
? 12 + base * 50 * (0.4 + 0.6 * _c.value)
: 8.0;
return Container(
width: 5,
height: h,
margin: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(
color: scheme.primary,
borderRadius: BorderRadius.circular(3),
),
);
}),
);
},
),
),
const SizedBox(height: 40),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: scheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(16),
),
child: Text(
'"What\'s the weather like this weekend?"',
style: theme.textTheme.bodyLarge,
textAlign: TextAlign.center,
),
),
const Spacer(),
GestureDetector(
onTap: () => setState(() => _listening = !_listening),
child: Container(
width: 84,
height: 84,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _listening ? scheme.primary : scheme.surfaceContainerHighest,
),
child: Icon(
_listening ? Icons.mic : Icons.mic_off,
size: 40,
color: _listening ? scheme.onPrimary : scheme.onSurface,
),
),
),
const SizedBox(height: 24),
],
),
),
);
}
}
Add it to your project
Copies the Dart source into your app, so you own it. Flutter SDK only, no extra packages.
First time? Run dart pub global activate fluttertemplates_dev, or read the CLI guide.
How it works
There’s no microphone or speech code. _listening toggles from the mic GestureDetector, and the 24 bars are a fixed sin curve scaled by a repeating AnimationController, so the waveform has no connection to sound. The quoted transcript is a hardcoded string. _c also keeps running after the bars flatten to 8 px.
Adapting it
- Start and stop a recogniser such as speech_to_text where
_listeningflips, and show partial results in place of the literal quote. - Drive the bar height
hfrom the recogniser’s sound level instead of_c.value. - Stop
_cwhile_listeningis false to avoid rebuilding the bars for nothing.