Cheat Sheet ⭐
A comprehensive quick reference for Flutter development — common widgets, navigation commands, state management with setState & Provider, HTTP requests, and essential pubspec dependencies.
1. Common Widgets Quick Reference
A condensed reference of the most-used Flutter widgets and their key properties — ideal for quick lookups during development.
// ── LAYOUT ──────────────────────────────────────────
Scaffold(appBar:, body:, floatingActionButton:, bottomNavigationBar:, drawer:)
AppBar(title:, actions:[], leading:, backgroundColor:, elevation:)
SafeArea(child:) // Avoid notch/status bar overlap
Column(mainAxisAlignment:, crossAxisAlignment:, children:[])
Row(mainAxisAlignment:, crossAxisAlignment:, children:[])
Stack(alignment:, children:[]) // Overlap widgets
Positioned(top:, left:, right:, bottom:, child:) // Inside Stack
Wrap(spacing:, runSpacing:, children:[]) // Auto-wrap children
GridView.count(crossAxisCount: 2, children:[])
ListView(children:[])
ListView.builder(itemCount:, itemBuilder: (ctx, i) => Widget)
ListView.separated(itemBuilder:, separatorBuilder:, itemCount:)
// ── CONTAINERS ────────────────────────────────────
Container(width:, height:, color:, padding:, margin:, decoration:, child:)
SizedBox(width:, height:, child:)
Padding(padding: EdgeInsets.all(16), child:)
Center(child:)
Align(alignment: Alignment.topRight, child:)
Expanded(flex: 1, child:)
Flexible(flex: 1, fit: FlexFit.tight, child:)
FractionallySizedBox(widthFactor: 0.8, child:)
// ── DISPLAY ──────────────────────────────────────
Text("str", style: TextStyle(fontSize:, fontWeight:, color:))
Icon(Icons.home, size: 24, color: Colors.blue)
Image.network("url", fit: BoxFit.cover)
Image.asset("assets/img.png")
CircleAvatar(radius: 30, backgroundImage: NetworkImage("url"))
Card(elevation: 4, shape: RoundedRectangleBorder(borderRadius:), child:)
Divider(height: 1, color: Colors.grey)
CircularProgressIndicator(color: Colors.blue)
LinearProgressIndicator(value: 0.7)
// ── INPUTS ───────────────────────────────────────
TextFormField(controller:, keyboardType:, obscureText:, validator:, decoration:)
Checkbox(value: _checked, onChanged: (v) => setState(() => _checked = v))
Switch(value: _on, onChanged: (v) => setState(() => _on = v))
Slider(value: _val, min: 0, max: 100, onChanged: (v) => setState(() => _val = v))
DropdownButton(value: _sel, items: [], onChanged: (v) => setState(() => _sel = v))
// ── BUTTONS ──────────────────────────────────────
ElevatedButton(onPressed:, child:, style: ElevatedButton.styleFrom(backgroundColor:))
TextButton(onPressed:, child:)
OutlinedButton(onPressed:, child:)
IconButton(onPressed:, icon: Icon(Icons.add))
FloatingActionButton(onPressed:, child: Icon(Icons.add))
GestureDetector(onTap:, onLongPress:, child:)
InkWell(onTap:, borderRadius:, child:)
2. Navigation Commands Cheat Sheet
All navigation operations in one place — pushing, popping, replacing, and passing arguments between screens.
// ── BASIC NAVIGATION ────────────────────────────────
// Push new screen onto stack
Navigator.push(context, MaterialPageRoute(builder: (_) => Screen()));
// Replace current screen (no back button)
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => Screen()));
// Go back
Navigator.pop(context);
// Go back with data
Navigator.pop(context, "returned_value");
// Get data from pop
final result = await Navigator.push(...);
// Clear all routes and go to new screen
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => LoginScreen()),
(route) => false,
);
// ── NAMED ROUTES ─────────────────────────────────
Navigator.pushNamed(context, "/home");
Navigator.pushReplacementNamed(context, "/home");
Navigator.pushNamedAndRemoveUntil(context, "/login", (r) => false);
// Named route with arguments
Navigator.pushNamed(context, "/detail", arguments: {"id": 1});
// Read arguments in destination
final args = ModalRoute.of(context)!.settings.arguments as Map;
// ── CHECK & CONTROL STACK ────────────────────────
Navigator.canPop(context) // Returns bool
Navigator.maybePop(context) // Pops if can, otherwise does nothing
Navigator.of(context).popUntil((route) => route.isFirst); // Pop to first
// ── CUSTOM PAGE TRANSITIONS ──────────────────────
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (_, anim, __) => const DetailScreen(),
transitionsBuilder: (_, anim, __, child) {
return FadeTransition(opacity: anim, child: child);
},
transitionDuration: const Duration(milliseconds: 400),
),
);
3. State Management – setState
setState is the simplest form of state management. Use it for local UI state within a single widget. Always call it inside a StatefulWidget and avoid heavy computation inside the callback.
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
bool _isLoading = false;
String _message = "";
List<String> _items = [];
// Simple increment
void _increment() {
setState(() {
_count++;
});
}
// Async operation with loading state
Future<void> _fetchData() async {
setState(() => _isLoading = true);
await Future.delayed(const Duration(seconds: 2)); // Simulate API
final data = ["Item 1", "Item 2", "Item 3"];
setState(() {
_items = data;
_isLoading = false;
_message = "Loaded ${data.length} items";
});
}
// Toggle boolean
void _toggle() => setState(() => _isLoading = !_isLoading);
// Add to list
void _addItem(String item) {
setState(() => _items.add(item));
}
// Remove from list
void _removeItem(int index) {
setState(() => _items.removeAt(index));
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Count: $_count"),
Text(_message),
if (_isLoading) const CircularProgressIndicator(),
...(_items.map((item) => Text(item))),
ElevatedButton(onPressed: _increment, child: const Text("+")),
ElevatedButton(onPressed: _fetchData, child: const Text("Fetch")),
],
);
}
}
4. State Management – Provider
Provider is the recommended approach for sharing state across multiple widgets. Define a ChangeNotifier, wrap your app with ChangeNotifierProvider, and consume state with Consumer or context.watch.
// 1. Create a ChangeNotifier
// lib/providers/counter_provider.dart
import "package:flutter/foundation.dart";
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // Rebuild listening widgets
}
void decrement() {
if (_count > 0) _count--;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}
// 2. Register provider in main.dart / app.dart
import "package:provider/provider.dart";
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
],
child: const MyApp(),
),
);
}
// 3a. Read state with context.watch (rebuilds on change)
class CounterDisplay extends StatelessWidget {
const CounterDisplay({super.key});
@override
Widget build(BuildContext context) {
final count = context.watch<CounterProvider>().count;
return Text("Count: $count");
}
}
// 3b. Read state with context.read (does NOT rebuild)
ElevatedButton(
onPressed: () {
context.read<CounterProvider>().increment();
},
child: const Text("Increment"),
)
// 3c. Use Consumer widget (fine-grained rebuild)
Consumer<CounterProvider>(
builder: (context, counter, child) {
return Text("Count: ${counter.count}");
},
)
// 3d. context.select – rebuild only when specific value changes
final count = context.select<CounterProvider, int>((p) => p.count);
5. HTTP Requests with http Package
Use the http package for REST API calls. Always handle errors and decode JSON responses. Create a dedicated service class to keep API logic separate from UI code.
import "dart:convert";
import "package:http/http.dart" as http;
class ApiService {
static const String _baseUrl = "https://api.example.com";
static const Map<String, String> _headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
// GET request
static Future<List<dynamic>> getItems() async {
final response = await http.get(
Uri.parse("$_baseUrl/items"),
headers: _headers,
);
if (response.statusCode == 200) {
return jsonDecode(response.body) as List;
} else {
throw Exception("Failed to load items: ${response.statusCode}");
}
}
// GET with auth token
static Future<Map<String, dynamic>> getProfile(String token) async {
final response = await http.get(
Uri.parse("$_baseUrl/profile"),
headers: {..._headers, "Authorization": "Bearer $token"},
);
return jsonDecode(response.body);
}
// POST request (login)
static Future<Map<String, dynamic>> login(String email, String pass) async {
final response = await http.post(
Uri.parse("$_baseUrl/login"),
headers: _headers,
body: jsonEncode({"email": email, "password": pass}),
);
final data = jsonDecode(response.body);
if (response.statusCode == 200) return data;
throw Exception(data["message"] ?? "Login failed");
}
// PUT / PATCH request
static Future<void> updateUser(int id, Map<String, dynamic> body) async {
await http.put(
Uri.parse("$_baseUrl/users/$id"),
headers: _headers,
body: jsonEncode(body),
);
}
// DELETE request
static Future<void> deleteItem(int id) async {
final response = await http.delete(
Uri.parse("$_baseUrl/items/$id"),
headers: _headers,
);
if (response.statusCode != 200) throw Exception("Delete failed");
}
}
// Usage in widget
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List _items = [];
bool _loading = true;
String? _error;
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
try {
final data = await ApiService.getItems();
setState(() { _items = data; _loading = false; });
} catch (e) {
setState(() { _error = e.toString(); _loading = false; });
}
}
@override
Widget build(BuildContext context) {
if (_loading) return const Center(child: CircularProgressIndicator());
if (_error != null) return Center(child: Text(_error!));
return ListView.builder(
itemCount: _items.length,
itemBuilder: (_, i) => ListTile(title: Text(_items[i].toString())),
);
}
}
6. Essential pubspec.yaml Dependencies
A curated list of the most commonly used Flutter packages across categories: networking, state management, navigation, storage, UI, and utilities.
dependencies:
flutter:
sdk: flutter
# ── NETWORKING ──────────────────────────────────
http: ^1.2.1 # Simple HTTP requests
dio: ^5.4.3 # Advanced HTTP (interceptors, cancel)
# ── STATE MANAGEMENT ────────────────────────────
provider: ^6.1.2 # Recommended simple state
riverpod: ^2.5.1 # Advanced, compile-safe state
flutter_bloc: ^8.1.5 # BLoC pattern
# ── NAVIGATION ──────────────────────────────────
go_router: ^13.2.0 # Declarative routing (deep links)
# ── LOCAL STORAGE ───────────────────────────────
shared_preferences: ^2.2.3 # Key-value storage (small data)
hive_flutter: ^1.1.0 # Fast NoSQL local database
sqflite: ^2.3.3 # SQLite for Flutter
flutter_secure_storage: ^9.0.0 # Encrypted storage (tokens)
# ── UI / DESIGN ─────────────────────────────────
cupertino_icons: ^1.0.6 # iOS-style icons
flutter_svg: ^2.0.10+1 # SVG image support
cached_network_image: ^3.3.1 # Network images with caching
shimmer: ^3.0.0 # Loading skeleton effect
lottie: ^3.1.0 # Lottie animations (JSON)
fl_chart: ^0.68.0 # Charts and graphs
flutter_slidable: ^3.1.0 # Swipeable list items
# ── FORMS & VALIDATION ──────────────────────────
flutter_form_builder: ^9.3.0 # Advanced form management
form_builder_validators: ^10.0.1 # Form validation rules
# ── SPLASH & ONBOARDING ─────────────────────────
flutter_native_splash: ^2.4.1 # Native splash screen
introduction_screen: ^3.1.14 # Onboarding slides
# ── PERMISSIONS & DEVICE ────────────────────────
permission_handler: ^11.3.1 # Request device permissions
geolocator: ^11.0.0 # GPS location
image_picker: ^1.1.1 # Camera & gallery picker
file_picker: ^8.0.6 # File picker
# ── NOTIFICATIONS ───────────────────────────────
firebase_messaging: ^15.0.4 # Push notifications (FCM)
flutter_local_notifications: ^17.2.2 # Local notifications
# ── UTILITIES ───────────────────────────────────
intl: ^0.19.0 # Date formatting, i18n
url_launcher: ^6.2.6 # Open URLs, phone, email
share_plus: ^9.0.0 # Share content
connectivity_plus: ^6.0.3 # Check network connectivity
package_info_plus: ^8.0.0 # Get app version info
path_provider: ^2.1.3 # File system paths
uuid: ^4.4.0 # Generate UUIDs
equatable: ^2.0.5 # Value equality for models
freezed_annotation: ^2.4.1 # Immutable data classes
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
build_runner: ^2.4.9 # Code generation
freezed: ^2.5.2 # Immutable class generator
json_serializable: ^6.7.6 # JSON model generator
hive_generator: ^2.0.1 # Hive adapter generator
7. Useful Snippets & Patterns
Everyday patterns: showing a snackbar, dialog, bottom sheet, checking theme mode, and formatting dates with intl.
// ── SNACKBAR ─────────────────────────────────────
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text("Saved successfully!"),
backgroundColor: Colors.green,
duration: const Duration(seconds: 3),
action: SnackBarAction(label: "Undo", onPressed: () {}),
),
);
// ── DIALOG ───────────────────────────────────────
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text("Confirm"),
content: const Text("Are you sure you want to delete this?"),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text("Cancel")),
ElevatedButton(
onPressed: () { Navigator.pop(ctx); /* do action */ },
child: const Text("Delete"),
),
],
),
);
// ── BOTTOM SHEET ─────────────────────────────────
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (ctx) => Container(
padding: const EdgeInsets.all(24),
child: const Text("Bottom Sheet Content"),
),
);
// ── DATE FORMAT (intl) ────────────────────────────
import "package:intl/intl.dart";
DateFormat("dd MMMM yyyy").format(DateTime.now()); // "08 June 2025"
DateFormat("HH:mm").format(DateTime.now()); // "14:30"
DateFormat("yyyy-MM-dd").format(DateTime.now()); // "2025-06-08"
// ── THEME & DARK MODE ────────────────────────────
final isDark = Theme.of(context).brightness == Brightness.dark;
final primaryColor = Theme.of(context).colorScheme.primary;
final textTheme = Theme.of(context).textTheme;
// ── MEDIA QUERY ──────────────────────────────────
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final padding = MediaQuery.of(context).padding; // Notch/navbar insets
// ── FUTURE BUILDER ───────────────────────────────
FutureBuilder<List>(
future: ApiService.getItems(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) return Text("Error: ${snapshot.error}");
final items = snapshot.data!;
return ListView.builder(
itemCount: items.length,
itemBuilder: (_, i) => ListTile(title: Text(items[i].toString())),
);
},
)