Flutter Cross-Platform UI AI Skill Guide
Overview & Engine Architecture
Flutter paints UI with a widget tree compiled to native ARM/x64 (and web/desktop targets). Everything is a widget; rebuilds are cheap when state is localized. Agents prefer composition over deep inheritance, choose an explicit state approach (Riverpod/Bloc/Provider) and stick to it, and keep platform-specific code behind clean facades.
Dart app
-> Widget tree (build)
-> Element / RenderObject
-> Skia / Impeller
-> iOS / Android / Web / Desktop
When to use this skill
- Building or refactoring Flutter screens
- Fixing unnecessary rebuilds and async UI races
- Adding platform views or method channels carefully
- Preparing release/signing build configs
Operational directives
- Keep
build()pure - no side effects; trigger work from callbacks/initState/providers. - Use
constconstructors where possible to cut rebuild cost. - Handle loading/error/empty states explicitly for every async boundary.
- Do not block the UI isolate with heavy JSON/parse - use compute/isolates when needed.
- Match Flutter/Dart SDK constraints in CI to local
pubspecconstraints.
Widget sketch
class ItemCount extends StatelessWidget {
const ItemCount({super.key, required this.qty});
final int qty;
@override
Widget build(BuildContext context) {
return Text('Qty: $qty');
}
}
class AddItemButton extends StatefulWidget {
const AddItemButton({super.key, required this.onAdd});
final Future<void> Function() onAdd;
@override
State<AddItemButton> createState() => _AddItemButtonState();
}
class _AddItemButtonState extends State<AddItemButton> {
bool _busy = false;
Future<void> _handle() async {
if (_busy) return;
setState(() => _busy = true);
try {
await widget.onAdd();
} finally {
if (mounted) setState(() => _busy = false);
}
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _busy ? null : _handle,
child: Text(_busy ? 'Saving...' : 'Add'),
);
}
}
Commands
flutter doctor
flutter pub get
flutter run
flutter test
flutter build apk
flutter build ipa
Common pitfalls
| Pitfall | Why it hurts | Fix |
|---|---|---|
| setState after dispose | Crashes | Check mounted |
| Giant Build methods | Unmaintainable rebuilds | Extract widgets |
| Ignoring null-safety | Runtime surprises | Sound null safety |
| Unsigned release experiments | Store rejection | Proper signing configs |
Best practices
- Use keys when reordering lists of stateful children.
- Centralize theme and text styles; avoid one-off magic numbers.
- Add golden/widget tests for critical UI; integration tests for flows.
- Document min iOS/Android OS versions for the project.
Limitations
- Plugin quality varies across platforms - verify each target.
- Impeller vs Skia behavior can differ by Flutter version/OS.
- Heavy native UI embedding is still a specialized path.
Related skills
@dart- language fundamentals when present@android-studio/@xcode-ios- native tooling underneath@firebase- common backend for Flutter apps