Flutter

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.

dart
// ── 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.

dart
// ── 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.

dart
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.

dart
// 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.

dart
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.

yaml
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.

dart
// ── 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())),
    );
  },
)