Flutter Cheatsheet
Overview
Flutter is Google's UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase. It uses the Dart programming language and provides a rich set of pre-designed widgets.
Installation
Prerequisites
# Check system requirements
flutter doctor
# Install Git
git --version
Install Flutter SDK
# macOS
# Download Flutter SDK from flutter.dev
# Extract to desired location
export PATH="$PATH:`pwd`/flutter/bin"
# Add to shell profile
echo 'export PATH="$PATH:/path/to/flutter/bin"' >> ~/.zshrc
source ~/.zshrc
# Linux
sudo snap install flutter --classic
# Windows
# Download Flutter SDK
# Extract and add to PATH
IDE Setup
# VS Code extensions
code --install-extension Dart-Code.dart-code
code --install-extension Dart-Code.flutter
# Android Studio plugins
# Install Flutter and Dart plugins
Verification
flutter doctor
flutter --version
dart --version
Project Creation
Create New Project
# Create Flutter app
flutter create my_app
cd my_app
# Create with specific organization
flutter create --org com.exemple my_app
# Create with different platforms
flutter create --platforms android,ios,web my_app
# Create with template
flutter create --template=plugin my_plugin
flutter create --template=package my_package
Project Structure
my_app/
├── android/
├── ios/
├── web/
├── lib/
│ ├── main.dart
│ ├── models/
│ ├── screens/
│ ├── widgets/
│ └── services/
├── test/
├── assets/
│ ├── images/
│ └── fonts/
├── pubspec.yaml
└── README.md
Basic Dart syntaxe
Variables and Types
// Variable declarations
var name = 'Flutter';
String title = 'My App';
int count = 0;
double price = 99.99;
bool isActive = true;
List<String> items = ['item1', 'item2'];
Map<String, dynamic> user = \\\\{'name': 'John', 'age': 30\\\\};
// Nullable types
String? nullableName;
int? nullableCount;
// Late variables
late String Description;
// Constants
const String appName = 'My App';
final DateTime now = DateTime.now();
Functions
// Basic function
String greet(String name) \\\\{
return 'Hello, $name!';
\\\\}
// Arrow function
String greetShort(String name) => 'Hello, $name!';
// optional paramètres
String greetoptional(String name, [String? title]) \\\\{
return title != null ? 'Hello, $title $name!' : 'Hello, $name!';
\\\\}
// Named paramètres
String greetNamed(\\\\{required String name, String title = 'Mr.'\\\\}) \\\\{
return 'Hello, $title $name!';
\\\\}
// Async function
Future<String> fetchData() async \\\\{
await Future.delayed(Duration(seconds: 2));
return 'Data loaded';
\\\\}
Classes
class User \\\\{
final String name;
final int age;
String? email;
// Constructor
User(\\\\{required this.name, required this.age, this.email\\\\});
// Named constructor
User.guest() : name = 'Guest', age = 0;
// Method
String getDisplayName() \\\\{
return email != null ? '$name ($email)' : name;
\\\\}
// Getter
bool get isAdult => age >= 18;
// Setter
set userEmail(String email) => this.email = email;
@override
String toString() => 'User(name: $name, age: $age)';
\\\\}
// utilisation
final user = User(name: 'John', age: 25);
final guest = User.guest();
Basic Widgets
Stateless Widget
import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget \\\\{
final String title;
final VoidCallback? onTap;
const MyWidget(\\\\{
clé? clé,
required this.title,
this.onTap,
\\\\}) : super(clé: clé);
@override
Widget build(BuildContext context) \\\\{
return Container(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
title,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
if (onTap != null)
ElevatedButton(
onPressed: onTap,
child: const Text('Tap Me'),
),
],
),
);
\\\\}
\\\\}
Stateful Widget
class CounterWidget extends StatefulWidget \\\\{
final int initialValue;
const CounterWidget(\\\\{clé? clé, this.initialValue = 0\\\\}) : super(clé: clé);
@override
State<CounterWidget> createState() => _CounterWidgetState();
\\\\}
class _CounterWidgetState extends State<CounterWidget> \\\\{
late int _counter;
@override
void initState() \\\\{
super.initState();
_counter = widget.initialValue;
\\\\}
void _increment() \\\\{
setState(() \\\\{
_counter++;
\\\\});
\\\\}
void _decrement() \\\\{
setState(() \\\\{
_counter--;
\\\\});
\\\\}
@override
Widget build(BuildContext context) \\\\{
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Counter: $_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _decrement,
child: const Text('-'),
),
ElevatedButton(
onPressed: _increment,
child: const Text('+'),
),
],
),
],
);
\\\\}
\\\\}
Layout Widgets
Container and Padding
Container(
width: 200,
height: 100,
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: const Text('Hello Flutter'),
)
Row and Column
// Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.star),
Text('Rating'),
Text('4.5'),
],
)
// Column
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title'),
Text('Subtitle'),
ElevatedButton(
onPressed: () \\\\{\\\\},
child: Text('Action'),
),
],
)
Stack and Positioned
Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
top: 20,
right: 20,
child: Icon(Icons.favorite, color: Colors.red),
),
Positioned(
bottom: 20,
left: 20,
child: Text('Bottom Left'),
),
],
)
Flexible and Expanded
Row(
children: [
Flexible(
flex: 1,
child: Container(color: Colors.red, height: 100),
),
Expanded(
flex: 2,
child: Container(color: Colors.green, height: 100),
),
Flexible(
flex: 1,
child: Container(color: Colors.blue, height: 100),
),
],
)
Common Widgets
Text and RichText
// Basic text
Text(
'Hello Flutter',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
)
// Rich text
RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: [
TextSpan(text: 'Hello '),
TextSpan(
text: 'Flutter',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
),
)
Buttons
// Elevated Button
ElevatedButton(
onPressed: () \\\\{
print('Button pressed');
\\\\},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
),
child: Text('Elevated Button'),
)
// Text Button
TextButton(
onPressed: () \\\\{\\\\},
child: Text('Text Button'),
)
// Outlined Button
OutlinedButton(
onPressed: () \\\\{\\\\},
child: Text('Outlined Button'),
)
// Icon Button
IconButton(
onPressed: () \\\\{\\\\},
icon: Icon(Icons.favorite),
)
// Floating Action Button
FloatingActionButton(
onPressed: () \\\\{\\\\},
child: Icon(Icons.add),
)
Input Widgets
// TextField
TextField(
decoration: InputDecoration(
labelText: 'Enter your name',
hintText: 'John Doe',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.person),
),
onChanged: (value) \\\\{
print('Input: $value');
\\\\},
)
// TextFormField with validation
TextFormField(
validator: (value) \\\\{
| if (value == null | | value.isEmpty) \\\\{ |
return 'Please enter some text';
\\\\}
return null;
\\\\},
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
)
// Checkbox
Checkbox(
value: isChecked,
onChanged: (bool? value) \\\\{
setState(() \\\\{
isChecked = value ?? false;
\\\\});
\\\\},
)
// Switch
Switch(
value: isSwitched,
onChanged: (bool value) \\\\{
setState(() \\\\{
isSwitched = value;
\\\\});
\\\\},
)
// Slider
Slider(
value: sliderValue,
min: 0,
max: 100,
divisions: 10,
label: sliderValue.round().toString(),
onChanged: (double value) \\\\{
setState(() \\\\{
sliderValue = value;
\\\\});
\\\\},
)
Lists and Grids
ListView
// Basic ListView
ListView(
children: [
ListTile(
leading: Icon(Icons.person),
title: Text('John Doe'),
subtitle: Text('john@exemple.com'),
trailing: Icon(Icons.arrow_forward),
onTap: () \\\\{\\\\},
),
ListTile(
leading: Icon(Icons.person),
title: Text('Jane Smith'),
subtitle: Text('jane@exemple.com'),
trailing: Icon(Icons.arrow_forward),
onTap: () \\\\{\\\\},
),
],
)
// ListView.builder
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) \\\\{
return ListTile(
title: Text(items[index].title),
subtitle: Text(items[index].Description),
onTap: () \\\\{
// Handle tap
\\\\},
);
\\\\},
)
// ListView.separated
ListView.separated(
itemCount: items.length,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (context, index) \\\\{
return ListTile(
title: Text(items[index]),
);
\\\\},
)
GridView
// GridView.count
GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: List.generate(20, (index) \\\\{
return Container(
decoration: BoxDecoration(
color: Colors.blue[100],
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text('Item $index'),
),
);
\\\\}),
)
// GridView.builder
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: items.length,
itemBuilder: (context, index) \\\\{
return Card(
child: Column(
children: [
Image.network(items[index].imageUrl),
Text(items[index].title),
],
),
);
\\\\},
)
Navigation
Basic Navigation
// Navigate to new screen
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
// Navigate with data
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(item: selectedItem),
),
);
// Navigate and replace
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
// Pop back
Navigator.pop(context);
// Pop with result
Navigator.pop(context, 'result data');
Named Routes
// main.dart
MaterialApp(
initialRoute: '/',
routes: \\\\{
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
'/third': (context) => ThirdScreen(),
\\\\},
)
// Navigate using named routes
Navigator.pushNamed(context, '/second');
// Navigate with arguments
Navigator.pushNamed(
context,
'/detail',
arguments: \\\\{'id': 123, 'title': 'Item Title'\\\\},
);
// Extract arguments
class DetailScreen extends StatelessWidget \\\\{
@override
Widget build(BuildContext context) \\\\{
final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return Scaffold(
appBar: AppBar(title: Text(args['title'])),
body: Text('ID: $\\\\{args['id']\\\\}'),
);
\\\\}
\\\\}
Advanced Navigation
// Navigate and clear stack
Navigator.pushNamedAndRemoveUntil(
context,
'/home',
(route) => false,
);
// Navigate with custom transition
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => SecondScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) \\\\{
return SlideTransition(
position: animation.drive(
Tween(begin: Offset(1.0, 0.0), end: Offset.zero),
),
child: child,
);
\\\\},
),
);
State Management
setState
class CounterScreen extends StatefulWidget \\\\{
@override
_CounterScreenState createState() => _CounterScreenState();
\\\\}
class _CounterScreenState extends State<CounterScreen> \\\\{
int _counter = 0;
void _incrementCounter() \\\\{
setState(() \\\\{
_counter++;
\\\\});
\\\\}
@override
Widget build(BuildContext context) \\\\{
return Scaffold(
body: Center(
child: Text('Counter: $_counter'),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
\\\\}
\\\\}
Provider
# pubspec.yaml
dependencies:
provider: ^6.0.5
// Model
class Counter extends ChangeNotifier \\\\{
int _count = 0;
int get count => _count;
void increment() \\\\{
_count++;
notifyListeners();
\\\\}
void decrement() \\\\{
_count--;
notifyListeners();
\\\\}
\\\\}
// main.dart
void main() \\\\{
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
\\\\}
// Consumer widget
class CounterScreen extends StatelessWidget \\\\{
@override
Widget build(BuildContext context) \\\\{
return Scaffold(
body: Center(
child: Consumer<Counter>(
builder: (context, counter, child) \\\\{
return Text('Count: $\\\\{counter.count\\\\}');
\\\\},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () \\\\{
Provider.of<Counter>(context, listen: false).increment();
\\\\},
child: Icon(Icons.add),
),
);
\\\\}
\\\\}
Riverpod
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.4.9
import 'package:flutter_riverpod/flutter_riverpod.dart';
// Provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) \\\\{
return CounterNotifier();
\\\\});
class CounterNotifier extends StateNotifier<int> \\\\{
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
\\\\}
// main.dart
void main() \\\\{
runApp(
ProviderScope(
child: MyApp(),
),
);
\\\\}
// Consumer widget
class CounterScreen extends ConsumerWidget \\\\{
@override
Widget build(BuildContext context, WidgetRef ref) \\\\{
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Text('Count: $count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () \\\\{
ref.read(counterProvider.notifier).increment();
\\\\},
child: Icon(Icons.add),
),
);
\\\\}
\\\\}
HTTP Requests
Basic HTTP
# pubspec.yaml
dependencies:
http: ^1.1.0
import 'package:http/http.dart' as http;
import 'dart:convert';
class Apiservice \\\\{
static const String baseUrl = 'https://jsonplaceholder.typicode.com';
static Future<List<Post>> fetchPosts() async \\\\{
final response = await http.get(Uri.parse('$baseUrl/posts'));
if (response.statusCode == 200) \\\\{
final List<dynamic> jsonData = json.decode(response.body);
return jsonData.map((json) => Post.fromJson(json)).toList();
\\\\} else \\\\{
throw Exception('Failed to load posts');
\\\\}
\\\\}
static Future<Post> createPost(Post post) async \\\\{
final response = await http.post(
Uri.parse('$baseUrl/posts'),
headers: \\\\{'Content-Type': 'application/json'\\\\},
body: json.encode(post.toJson()),
);
if (response.statusCode == 201) \\\\{
return Post.fromJson(json.decode(response.body));
\\\\} else \\\\{
throw Exception('Failed to create post');
\\\\}
\\\\}
static Future<void> deletePost(int id) async \\\\{
final response = await http.delete(Uri.parse('$baseUrl/posts/$id'));
if (response.statusCode != 200) \\\\{
throw Exception('Failed to delete post');
\\\\}
\\\\}
\\\\}
// Model
class Post \\\\{
final int id;
final String title;
final String body;
Post(\\\\{required this.id, required this.title, required this.body\\\\});
factory Post.fromJson(Map<String, dynamic> json) \\\\{
return Post(
id: json['id'],
title: json['title'],
body: json['body'],
);
\\\\}
Map<String, dynamic> toJson() \\\\{
return \\\\{
'id': id,
'title': title,
'body': body,
\\\\};
\\\\}
\\\\}
FutureBuilder
class PostsList extends StatelessWidget \\\\{
@override
Widget build(BuildContext context) \\\\{
return Scaffold(
appBar: AppBar(title: Text('Posts')),
body: FutureBuilder<List<Post>>(
future: Apiservice.fetchPosts(),
builder: (context, snapshot) \\\\{
if (snapshot.connexionState == connexionState.waiting) \\\\{
return Center(child: CircularProgressIndicator());
\\\\} else if (snapshot.hasError) \\\\{
return Center(child: Text('Error: $\\\\{snapshot.error\\\\}'));
| \\\\} else if (!snapshot.hasData | | snapshot.data!.isEmpty) \\\\{ |
return Center(child: Text('No posts found'));
\\\\} else \\\\{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) \\\\{
final post = snapshot.data![index];
return ListTile(
title: Text(post.title),
subtitle: Text(post.body),
);
\\\\},
);
\\\\}
\\\\},
),
);
\\\\}
\\\\}
Local Storage
SharedPréférences
# pubspec.yaml
dependencies:
shared_préférences: ^2.2.2
import 'package:shared_préférences/shared_préférences.dart';
class Préférencesservice \\\\{
static Future<void> saveString(String clé, String value) async \\\\{
final prefs = await SharedPréférences.getInstance();
await prefs.setString(clé, value);
\\\\}
static Future<String?> getString(String clé) async \\\\{
final prefs = await SharedPréférences.getInstance();
return prefs.getString(clé);
\\\\}
static Future<void> saveInt(String clé, int value) async \\\\{
final prefs = await SharedPréférences.getInstance();
await prefs.setInt(clé, value);
\\\\}
static Future<int?> getInt(String clé) async \\\\{
final prefs = await SharedPréférences.getInstance();
return prefs.getInt(clé);
\\\\}
static Future<void> saveBool(String clé, bool value) async \\\\{
final prefs = await SharedPréférences.getInstance();
await prefs.setBool(clé, value);
\\\\}
static Future<bool?> getBool(String clé) async \\\\{
final prefs = await SharedPréférences.getInstance();
return prefs.getBool(clé);
\\\\}
static Future<void> remove(String clé) async \\\\{
final prefs = await SharedPréférences.getInstance();
await prefs.remove(clé);
\\\\}
static Future<void> clear() async \\\\{
final prefs = await SharedPréférences.getInstance();
await prefs.clear();
\\\\}
\\\\}
SQLite Database
# pubspec.yaml
dependencies:
sqflite: ^2.3.0
path: ^1.8.3
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper \\\\{
static Database? _database;
static const String tableName = 'users';
static Future<Database> get database async \\\\{
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
\\\\}
static Future<Database> _initDatabase() async \\\\{
String path = join(await getDatabasesPath(), 'app_database.db');
return await openDatabase(
path,
version: 1,
onCreate: _createDatabase,
);
\\\\}
static Future<void> _createDatabase(Database db, int version) async \\\\{
await db.execute('''
CREATE TABLE $tableName (
id INTEGER PRIMARY clé AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
created_at TEXT NOT NULL
)
''');
\\\\}
static Future<int> insertUser(User user) async \\\\{
final db = await database;
return await db.insert(tableName, user.toMap());
\\\\}
static Future<List<User>> getAllUsers() async \\\\{
final db = await database;
final List<Map<String, dynamic>> maps = await db.query(tableName);
return List.generate(maps.length, (i) => User.fromMap(maps[i]));
\\\\}
static Future<User?> getUserById(int id) async \\\\{
final db = await database;
final List<Map<String, dynamic>> maps = await db.query(
tableName,
where: 'id = ?',
whereArgs: [id],
);
if (maps.isNotEmpty) \\\\{
return User.fromMap(maps.first);
\\\\}
return null;
\\\\}
static Future<int> updateUser(User user) async \\\\{
final db = await database;
return await db.update(
tableName,
user.toMap(),
where: 'id = ?',
whereArgs: [user.id],
);
\\\\}
static Future<int> deleteUser(int id) async \\\\{
final db = await database;
return await db.delete(
tableName,
where: 'id = ?',
whereArgs: [id],
);
\\\\}
\\\\}
class User \\\\{
final int? id;
final String name;
final String email;
final DateTime createdAt;
User(\\\\{
this.id,
required this.name,
required this.email,
required this.createdAt,
\\\\});
Map<String, dynamic> toMap() \\\\{
return \\\\{
'id': id,
'name': name,
'email': email,
'created_at': createdAt.toIso8601String(),
\\\\};
\\\\}
factory User.fromMap(Map<String, dynamic> map) \\\\{
return User(
id: map['id'],
name: map['name'],
email: map['email'],
createdAt: DateTime.parse(map['created_at']),
);
\\\\}
\\\\}
Testing
Unit Testing
// test/counter_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter.dart';
void main() \\\\{
group('Counter', () \\\\{
test('should start with 0', () \\\\{
final counter = Counter();
expect(counter.value, 0);
\\\\});
test('should increment', () \\\\{
final counter = Counter();
counter.increment();
expect(counter.value, 1);
\\\\});
test('should decrement', () \\\\{
final counter = Counter();
counter.increment();
counter.decrement();
expect(counter.value, 0);
\\\\});
\\\\});
\\\\}
Widget Testing
// test/widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart';
void main() \\\\{
testWidgets('Counter increments smoke test', (WidgetTester tester) async \\\\{
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
\\\\});
testWidgets('Should display error message when input is empty', (WidgetTester tester) async \\\\{
await tester.pumpWidget(MaterialApp(home: LoginForm()));
// Find the submit button and tap it without entering text
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
// Verify error message is displayed
expect(find.text('Please enter your email'), findsOneWidget);
\\\\});
\\\\}
Integration Testing
// integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;
void main() \\\\{
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('end-to-end test', () \\\\{
testWidgets('tap on the floating action button, verify counter', (tester) async \\\\{
app.main();
await tester.pumpAndSettle();
// Verify the counter starts at 0.
expect(find.text('0'), findsOneWidget);
// Finds the floating action button to tap on.
final Finder fab = find.byTooltip('Increment');
// Emulate a tap on the floating action button.
await tester.tap(fab);
// Trigger a frame.
await tester.pumpAndSettle();
// Verify the counter increments by 1.
expect(find.text('1'), findsOneWidget);
\\\\});
\\\\});
\\\\}
Build and Deployment
Android Build
# Debug build
flutter build apk --debug
# Release build
flutter build apk --release
# Build AAB (recommended for Play Store)
flutter build appbundle --release
# Install on device
flutter install
iOS Build
# Debug build
flutter build ios --debug
# Release build
flutter build ios --release
# Build for simulator
flutter build ios --simulator
Web Build
# Build for web
flutter build web
# Serve locally
flutter run -d chrome
Build configuration
# pubspec.yaml
flutter:
assets:
- assets/images/
- assets/fonts/
fonts:
- family: CustomFont
fonts:
- asset: assets/fonts/CustomFont-Regular.ttf
- asset: assets/fonts/CustomFont-Bold.ttf
weight: 700
# Build flavors
flutter build apk --flavor production --cible lib/main_production.dart
Performance Optimization
Widget Optimization
// Use const constructors
const Text('Hello World')
// Use ListView.builder for large lists
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) \\\\{
return ListTile(title: Text(items[index]));
\\\\},
)
// Use RepaintBoundary for expensive widgets
RepaintBoundary(
child: ExpensiveWidget(),
)
// Use AutomaticKeepAliveClientMixin for tabs
class MyTab extends StatefulWidget \\\\{
@override
_MyTabState createState() => _MyTabState();
\\\\}
class _MyTabState extends State<MyTab> with AutomaticKeepAliveClientMixin \\\\{
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) \\\\{
super.build(context);
return Container(/* tab content */);
\\\\}
\\\\}
Image Optimization
// Use cached network images
CachedNetworkImage(
imageUrl: 'https://exemple.com/image.jpg',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
// Optimize image loading
Image.network(
'https://exemple.com/image.jpg',
loadingBuilder: (context, child, loadingProgress) \\\\{
if (loadingProgress == null) return child;
return CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
);
\\\\},
)
Common commandes
Development
# Run app
flutter run
# Run on specific device
flutter run -d <device-id>
# Hot reload
r (in terminal)
# Hot restart
R (in terminal)
# Debug info
flutter doctor
flutter devices
flutter logs
Build and Test
# Run tests
flutter test
# Run integration tests
flutter test integration_test/
# Analyze code
flutter analyze
# Format code
flutter format .
# Clean project
flutter clean
# Get dependencies
flutter pub get
# Upgrade dependencies
flutter pub upgrade
Resources
- Documentation Officielle: flutter.dev
- Dart Language: dart.dev
- Widget Catalog: flutter.dev/docs/development/ui/widgets
- Pub.dev Packages: pub.dev