Flutter Development
Build beautiful, natively compiled applications for mobile, web, and desktop from a single codebase using Flutter and Dart.
When to use this Skill
Use this Skill when:
- Creating new Flutter applications
- Working with Flutter widgets and UI components
- Implementing state management (Provider, BLoC, Riverpod)
- Setting up navigation and routing
- Integrating APIs and HTTP requests
- Debugging Flutter applications
- Following Flutter best practices
- User mentions Flutter, Dart, mobile apps, iOS, Android, or cross-platform development
Project structure
Standard Flutter project:
my_flutter_app/
├── lib/
│ ├── main.dart # App entry point
│ ├── screens/ # Screen widgets
│ ├── widgets/ # Reusable widgets
│ ├── models/ # Data models
│ ├── services/ # API, database services
│ └── providers/ # State management
├── pubspec.yaml # Dependencies and assets
├── test/ # Unit and widget tests
└── assets/ # Images, fonts, etc.
Common Flutter commands
Create new project
flutter create my_app
cd my_app
Run application
flutter run # Default device
flutter run -d chrome # Web
flutter run -d linux # Linux desktop
flutter run -d android # Android device/emulator
Manage dependencies
flutter pub add package_name # Add dependency
flutter pub get # Install dependencies
flutter pub upgrade # Update dependencies
Testing and building
flutter test # Run tests
flutter analyze # Static analysis
flutter build apk # Android APK
flutter build ios # iOS build
flutter build web # Web build
Basic Flutter app template
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: const Center(
child: Text('Hello, Flutter!'),
),
);
}
}
State management with Provider
Install Provider:
flutter pub add provider
Example usage:
// 1. Create a ChangeNotifier model
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// 2. Wrap app with ChangeNotifierProvider
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: const MyApp(),
),
);
}
// 3. Access in widgets
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<Counter>();
return Text('Count: ${counter.count}');
}
}
// 4. Trigger updates
ElevatedButton(
onPressed: () => context.read<Counter>().increment(),
child: const Text('Increment'),
)
Navigation
Basic navigation
// Navigate to new screen
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondScreen()),
);
// Navigate back
Navigator.pop(context);
// Navigate with data
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(data: myData),
),
);
GoRouter (recommended for complex apps)
flutter pub add go_router
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return DetailScreen(id: id);
},
),
],
);
// Use in app
MaterialApp.router(
routerConfig: router,
)
// Navigate
context.go('/details/123');
HTTP requests
Install http package:
flutter pub add http
Example:
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List<User>> fetchUsers() async {
final response = await http.get(
Uri.parse('https://api.example.com/users'),
);
if (response.statusCode == 200) {
final List<dynamic> data = json.decode(response.body);
return data.map((json) => User.fromJson(json)).toList();
} else {
throw Exception('Failed to load users');
}
}
// Use with FutureBuilder
FutureBuilder<List<User>>(
future: fetchUsers(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(title: Text(snapshot.data![index].name));
},
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return const CircularProgressIndicator();
},
)
Essential widgets
Layout widgets
- Container - Box model with padding, margin, decoration
- Column - Vertical layout
- Row - Horizontal layout
- Stack - Layered widgets
- Expanded - Fills available space
- Padding - Adds padding around widget
- Center - Centers child widget
- SizedBox - Fixed size box or spacer
Input widgets
- TextField - Text input
- Form - Group input fields with validation
- Checkbox - Boolean selection
- Radio - Single choice from options
- Switch - Toggle on/off
- Slider - Select value from range
- DropdownButton - Select from dropdown
Display widgets
- Text - Display text with styling
- Image - Display images (network, asset, file)
- Icon - Material or custom icons
- Card - Material Design card
- ListTile - Standard list item
Interactive widgets
- ElevatedButton - Raised button with elevation
- TextButton - Flat text button
- IconButton - Button with icon
- FloatingActionButton - Floating action button
- GestureDetector - Detect gestures (tap, swipe, etc.)
- InkWell - Touch feedback with ripple
Async widgets
- FutureBuilder - Build based on Future
- StreamBuilder - Build based on Stream
Best practices
DO:
✅ Use const constructors wherever possible for better performance
✅ Implement proper dispose() methods to prevent memory leaks
✅ Extract widgets into separate classes for reusability
✅ Use meaningful, descriptive widget names
✅ Separate business logic from UI (use services/providers)
✅ Handle errors comprehensively with try-catch
✅ Test on both iOS and Android platforms
✅ Use responsive design (MediaQuery, LayoutBuilder)
✅ Follow Dart naming conventions (lowerCamelCase for variables, UpperCamelCase for classes)
✅ Add comments for complex logic
DON'T:
❌ Hardcode values (use constants or configuration) ❌ Use complex setState logic (prefer state management solutions) ❌ Make network calls in build() methods ❌ Skip testing phases ❌ Ignore platform-specific differences ❌ Create deeply nested widget trees (extract to methods/classes) ❌ Store heavy objects in state unnecessarily ❌ Forget to add loading and error states
Common patterns
Stateless vs Stateful widgets
- StatelessWidget: UI doesn't change, no mutable state
- StatefulWidget: UI changes based on state updates
Lifting state up
Move state to common ancestor when multiple widgets need access:
class Parent extends StatefulWidget {
@override
State<Parent> createState() => _ParentState();
}
class _ParentState extends State<Parent> {
int _count = 0;
void _increment() => setState(() => _count++);
@override
Widget build(BuildContext context) {
return Column(
children: [
ChildA(count: _count),
ChildB(onPressed: _increment),
],
);
}
}
Responsive design
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final isLargeScreen = size.width > 600;
return isLargeScreen
? Row(children: [...]) // Tablet/Desktop layout
: Column(children: [...]); // Mobile layout
}
Debugging tips
- Hot reload: Press
rin terminal or save file (for quick UI updates) - Hot restart: Press
Rin terminal (for state reset) - Flutter DevTools: Run
flutter pub global activate devtoolsthenflutter pub global run devtools - Debug print: Use
debugPrint()instead ofprint() - Widget inspector: Enable in DevTools to inspect widget tree
- Performance overlay:
flutter run --profilefor performance metrics
Instructions for Claude
When helping with Flutter development:
- Always check Flutter installation before creating projects
- Create proper project structure following Flutter conventions
- Use Material Design 3 (
useMaterial3: true) for modern UI - Implement responsive design considering different screen sizes
- Add proper error handling and loading states
- Use const constructors wherever possible
- Follow Dart naming conventions throughout the code
- Add helpful comments for complex logic
- Suggest appropriate state management based on app complexity
- Test code structure before suggesting advanced features
- Provide both code and explanations for learning
- Include pubspec.yaml changes when adding dependencies
Common issues and solutions
Issue: "Waiting for another flutter command to release the startup lock"
Solution: Delete flutter.lock file or restart terminal
Issue: "Gradle build failed"
Solution: Run flutter clean then flutter pub get
Issue: "setState called during build"
Solution: Move setState calls to lifecycle methods or use Future.microtask
Issue: "RenderBox overflow"
Solution: Wrap content in SingleChildScrollView or use Flexible/Expanded widgets
Issue: Hot reload not working
Solution: Use hot restart (R) or restart app completely