Introduction
Flutter has become the go-to framework for cross-platform mobile development, but even experienced developers often find themselves spending hours on boilerplate code, debugging state management issues, or tweaking animation curves. As a hands-on developer who uses AI daily, I've compiled a battle-tested collection of prompts that actually speed up real work — from widget composition to Bloc and Riverpod patterns. Each prompt comes with a concrete usage example, so you can copy-paste them into your AI assistant and get production-ready code immediately.
1. StatelessWidget with Custom Styling
Prompt: "Generate a Flutter StatelessWidget that displays a card with rounded corners, a shadow, and an icon on the left. The card must accept a title and subtitle as parameters. Use Theme.of(context) for colors."
Example output (simplified):
class InfoCard extends StatelessWidget {
final String title;
final String subtitle;
final IconData icon;
const InfoCard({required this.title, required this.subtitle, required this.icon});
@override
Widget build(BuildContext context) {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
leading: Icon(icon, color: Theme.of(context).primaryColor),
title: Text(title),
subtitle: Text(subtitle),
),
);
}
}
2. StatefulWidget with TextFormField Validation
Prompt: "Create a StatefulWidget with a Form and a TextFormField that validates an email address. Show a red error message below the field if invalid. Use a GlobalKey
Key snippet:
final _formKey = GlobalKey<FormState>();
String _email = '';
// Inside build:
Form(
key: _formKey,
child: TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (val) {
if (val == null || !val.contains('@')) return 'Enter a valid email';
return null;
},
onSaved: (val) => _email = val!,
),
)
3. AnimatedContainer for Smooth Transitions
Prompt: "Write an AnimatedContainer that changes its width and color when a bool toggles. Duration: 500ms. Use a CurvedAnimation with easeInOut."
Example:
AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
width: _isExpanded ? 300 : 100,
height: 50,
decoration: BoxDecoration(
color: _isExpanded ? Colors.blue : Colors.red,
borderRadius: BorderRadius.circular(8),
),
)
4. Hero Animation Between Screens
Prompt: "Create a Hero animation between two screens. The first screen has a circular avatar, the second screen shows a full-screen image of the same person. Use identical tags."
Screen 1:
Hero(
tag: 'avatar',
child: CircleAvatar(radius: 50, backgroundImage: NetworkImage('https://example.com/avatar.jpg')),
)
Screen 2:
Hero(
tag: 'avatar',
child: Image.network('https://example.com/avatar.jpg', fit: BoxFit.contain),
)
5. Bloc Pattern – Counter Example
Prompt: "Generate a simple Bloc counter with events Increment and Decrement. Use flutter_bloc. Include a CounterBloc class and a CounterScreen that listens to states."
CounterBloc:
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
on<Decrement>((event, emit) => emit(state - 1));
}
}
Screen integration:
BlocProvider(
create: (_) => CounterBloc(),
child: CounterScreen(),
);
6. Riverpod – Async Data Fetching
Prompt: "Write a Riverpod provider that fetches a list of users from a REST API using http package. Handle loading and error states in a Consumer widget."
Provider:
final userListProvider = FutureProvider<List<User>>((ref) async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
if (response.statusCode != 200) throw Exception('Failed to load');
return (json.decode(response.body) as List).map((e) => User.fromJson(e)).toList();
});
UI:
Consumer(
builder: (context, ref, _) {
final usersAsync = ref.watch(userListProvider);
return usersAsync.when(
data: (users) => ListView.builder(itemCount: users.length, itemBuilder: ...),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
},
);
7. Custom Animated Widget with AnimationController
Prompt: "Create a custom widget that fades in and slides up when mounted. Use AnimationController and Tween. The widget should start invisible and animate to full opacity and offset zero."
Implementation:
class FadeSlideIn extends StatefulWidget {
final Widget child;
final Duration duration;
const FadeSlideIn({required this.child, this.duration = const Duration(milliseconds: 600)});
@override
State<FadeSlideIn> createState() => _FadeSlideInState();
}
class _FadeSlideInState extends State<FadeSlideIn> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _opacity;
late Animation<Offset> _offset;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: widget.duration);
_opacity = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_offset = Tween<Offset>(begin: Offset(0, 0.3), end: Offset.zero).animate(_controller);
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) => Opacity(
opacity: _opacity.value,
child: Transform.translate(offset: _offset.value, child: child),
),
child: widget.child,
);
}
}
8. Provider for Theme Toggle
Prompt: "Use the Provider package to create a theme notifier that toggles between light and dark mode. Provide it at the MaterialApp level."
Model:
class ThemeNotifier extends ChangeNotifier {
ThemeMode _mode = ThemeMode.light;
ThemeMode get mode => _mode;
void toggle() {
_mode = _mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
Usage:
ChangeNotifierProvider(
create: (_) => ThemeNotifier(),
child: Consumer<ThemeNotifier>(
builder: (context, theme, _) => MaterialApp(
themeMode: theme.mode,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
),
),
);
9. Custom Paint for Drawing
Prompt: "Write a CustomPainter that draws a simple pie chart with 3 segments. Each segment has a different color. The segments are defined by a list of doubles (values)."
Painter:
class PieChartPainter extends CustomPainter {
final List<double> values;
final List<Color> colors;
@override
void paint(Canvas canvas, Size size) {
final total = values.reduce((a,b) => a+b);
double startAngle = -pi / 2;
final rect = Rect.fromLTWH(0, 0, size.width, size.height);
for (int i = 0; i < values.length; i++) {
final sweepAngle = (values[i] / total) * 2 * pi;
canvas.drawArc(rect, startAngle, sweepAngle, true, Paint()..color = colors[i]);
startAngle += sweepAngle;
}
}
@override
bool shouldRepaint(covariant PieChartPainter oldDelegate) => oldDelegate.values != values;
}
10. SliverAppBar with Collapsing Toolbar
Prompt: "Create a CustomScrollView with a SliverAppBar that collapses on scroll. The app bar has a background image and a title that fades in when expanded."
Implementation:
CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
background: Image.network('https://example.com/cover.jpg', fit: BoxFit.cover),
title: Text('My Profile'),
),
pinned: true,
),
SliverList(delegate: SliverChildBuilderDelegate(..., childCount: 20)),
],
);
11. StreamBuilder for Real-Time Data
Prompt: "Use StreamBuilder to display a list of messages from a Firestore collection. Show a loading indicator while waiting, and a 'No messages' text when empty."
Code:
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return CircularProgressIndicator();
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) return Text('No messages');
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) => Text(snapshot.data!.docs[index]['text']),
);
},
);
12. Staggered Animation with Multiple Controllers
Prompt: "Create a staggered animation where three containers slide in from the left one after another, each delayed by 200ms. Use a single AnimationController."
Key logic:
final List<Interval> intervals = [
Interval(0.0, 0.3),
Interval(0.2, 0.5),
Interval(0.4, 0.7),
];
// For each item:
SlideTransition(
position: Tween<Offset>(
begin: Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(parent: _controller, curve: intervals[i])),
child: ...
)
13. Internationalization (i18n) with Provider
Prompt: "Implement locale switching using Provider and the intl package. Provide a LocaleNotifier that can change the locale and rebuilds the MaterialApp."
Notifier:
class LocaleNotifier extends ChangeNotifier {
Locale _locale = Locale('en');
Locale get locale => _locale;
void setLocale(Locale locale) {
_locale = locale;
notifyListeners();
}
}
Usage:
Consumer<LocaleNotifier>(
builder: (context, localeNotifier, _) => MaterialApp(
locale: localeNotifier.locale,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
],
supportedLocales: [Locale('en'), Locale('ru')],
),
);
14. Responsive Layout with LayoutBuilder
Prompt: "Write a LayoutBuilder that returns a Row on wide screens and a Column on narrow screens (breakpoint at 600px). The children are an image and a text block."
Code:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(children: [Image(...), Text('...')]);
} else {
return Column(children: [Image(...), Text('...')]);
}
},
);
15. Testing a Bloc with Fake Data
Prompt: "Write a unit test for a CounterBloc using bloc_test. Test that Increment event increases state by 1 and Decrement decreases by 1."
Test:
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
);
blocTest<CounterBloc, int>(
'emits [-1] when Decrement is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Decrement()),
expect: () => [-1],
);
Conclusion
These 15 prompts cover the most common Flutter tasks I encounter daily. By feeding them to your AI assistant, you can cut boilerplate generation time by half and focus on the unique logic of your app. The key is to be specific about widget names, state management patterns, and animation parameters. Copy, paste, customize — and ship faster.
ASI Biont supports connecting your Flutter app to external services like Firebase or REST APIs through custom integrations — learn more at asibiont.com/courses.
Comments