Appearance
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
bash
# Check system requirements
flutter doctor
# Install Git
git --version
Install Flutter SDK
bash
# 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
bash
# 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
bash
flutter doctor
flutter --version
dart --version
Project Creation
Create New Project
bash
# Create Flutter app
flutter create my_app
cd my_app
# Create with specific organization
flutter create --org com.example 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 Syntax
Variables and Types
dart
// 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
dart
// Basic function
String greet(String name) {
return 'Hello, $name!';
}
// Arrow function
String greetShort(String name) => 'Hello, $name!';
// Optional parameters
String greetOptional(String name, [String? title]) {
return title != null ? 'Hello, $title $name!' : 'Hello, $name!';
}
// Named parameters
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
dart
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)';
}
// Usage
final user = User(name: 'John', age: 25);
final guest = User.guest();
Basic Widgets
Stateless Widget
dart
import 'package:flutter/material.dart';
class MyWidget extends StatelessWidget {
final String title;
final VoidCallback? onTap;
const MyWidget({
Key? key,
required this.title,
this.onTap,
}) : super(key: key);
@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
dart
class CounterWidget extends StatefulWidget {
final int initialValue;
const CounterWidget({Key? key, this.initialValue = 0}) : super(key: key);
@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
dart
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
dart
// 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
dart
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
dart
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
dart
// 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
dart
// 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
dart
// 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
dart
// Basic ListView
ListView(
children: [
ListTile(
leading: Icon(Icons.person),
title: Text('John Doe'),
subtitle: Text('john@example.com'),
trailing: Icon(Icons.arrow_forward),
onTap: () {},
),
ListTile(
leading: Icon(Icons.person),
title: Text('Jane Smith'),
subtitle: Text('jane@example.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
dart
// 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
dart
// 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
dart
// 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
dart
// 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
dart
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
yaml
# pubspec.yaml
dependencies:
provider: ^6.0.5
dart
// 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
yaml
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.4.9
dart
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
yaml
# pubspec.yaml
dependencies:
http: ^1.1.0
dart
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
dart
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.connectionState == ConnectionState.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
SharedPreferences
yaml
# pubspec.yaml
dependencies:
shared_preferences: ^2.2.2
dart
import 'package:shared_preferences/shared_preferences.dart';
class PreferencesService {
static Future<void> saveString(String key, String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
static Future<String?> getString(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
}
static Future<void> saveInt(String key, int value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(key, value);
}
static Future<int?> getInt(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(key);
}
static Future<void> saveBool(String key, bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, value);
}
static Future<bool?> getBool(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(key);
}
static Future<void> remove(String key) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(key);
}
static Future<void> clear() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
}
SQLite Database
yaml
# pubspec.yaml
dependencies:
sqflite: ^2.3.0
path: ^1.8.3
dart
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 KEY 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
dart
// 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
dart
// 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
dart
// 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
bash
# 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
bash
# Debug build
flutter build ios --debug
# Release build
flutter build ios --release
# Build for simulator
flutter build ios --simulator
Web Build
bash
# Build for web
flutter build web
# Serve locally
flutter run -d chrome
Build Configuration
yaml
# 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 --target lib/main_production.dart
Performance Optimization
Widget Optimization
dart
// 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
dart
// Use cached network images
CachedNetworkImage(
imageUrl: 'https://example.com/image.jpg',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
// Optimize image loading
Image.network(
'https://example.com/image.jpg',
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
);
},
)
Common Commands
Development
bash
# 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
bash
# 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
- Official Documentation: flutter.dev
- Dart Language: dart.dev
- Widget Catalog: flutter.dev/docs/development/ui/widgets
- Pub.dev Packages: pub.dev