C
h
i
L
L
u
.
.
.
Flutter's Language

The Complete Dart & Flutter Guide

Master Dart — Google's client-optimized language powering Flutter for building natively compiled apps across mobile, web, and desktop from a single codebase.

Why Learn Dart?

Dart was created by Google and unveiled in 2011. It was designed as a structured, flexible language for the modern web. Today, Dart is best known as the language behind Flutter — Google's UI toolkit that allows building beautiful, natively compiled applications from a single Dart codebase.

Dart features sound null safety, a strong type system, async/await for asynchronous programming, and compiles to native ARM code for mobile, native x64 for desktop, and JavaScript for web. Flutter apps built with Dart achieve near-native performance.

Dart is used by Google Pay, eBay Motors, and thousands of apps on the App Store and Google Play — all from a single Dart codebase.

Quick start: Install Flutter SDK which includes Dart. Run flutter create my_app to get started.

1. Dart Basics & Variables

Variables, Types, and Control Flow

Dart is statically typed with type inference via var. It supports final (runtime constant) and const (compile-time constant). All types are non-nullable by default with sound null safety.

void main() {
  // Type inference
  var name = 'Flutter Dev';     // String
  var age = 25;                 // int
  var height = 5.9;             // double
  var isActive = true;          // bool

  // Explicit types
  String language = 'Dart';
  int year = 2024;

  // Constants
  final pi = 3.14159;           // runtime constant
  const appName = 'MyFlutterApp'; // compile-time constant

  // String interpolation
  print('Hello, $name! You are $age years old.');
  print('2 + 2 = ${2 + 2}');

  // Null safety — nullable types use ?
  String? nullableStr = null;
  print(nullableStr?.toUpperCase() ?? 'no value');

  // Control flow
  for (var i = 1; i <= 5; i++) {
    if (i % 2 == 0) {
      print('$i is even');
    } else {
      print('$i is odd');
    }
  }

  var fruits = ['apple', 'banana', 'mango'];
  for (var fruit in fruits) {
    print(fruit);
  }
}

2. Collections & Null Safety

Lists, Maps, Sets, and Null Safety

Dart collections are generic and type-safe. The spread operator and collection-if/for in collection literals make building lists expressive and clean.

void main() {
  // List
  List<String> colors = ['red', 'green', 'blue'];
  colors.add('yellow');
  colors.removeAt(0);
  print(colors.length);

  // Functional methods
  var numbers = [1, 2, 3, 4, 5, 6];
  var evens = numbers.where((n) => n.isEven).toList();
  var doubled = numbers.map((n) => n * 2).toList();
  var sum = numbers.reduce((a, b) => a + b);
  print('Evens: $evens, Sum: $sum');

  // Map (key-value pairs)
  Map<String, int> scores = {'Alice': 95, 'Bob': 82, 'Carol': 88};
  scores['Dave'] = 91;
  scores.forEach((name, score) => print('$name: $score'));

  // Spread operator
  var list1 = [1, 2, 3];
  var list2 = [4, 5, 6];
  var combined = [...list1, ...list2]; // [1,2,3,4,5,6]

  // Collection-if
  var showExtras = true;
  var items = ['a', 'b', if (showExtras) 'c', 'd'];

  // Null safety patterns
  String? maybeNull = null;
  String safe = maybeNull ?? 'default';     // null coalescing
  String? upper = maybeNull?.toUpperCase(); // null-aware call
  String forced = maybeNull!;               // null assertion (throws if null)
}

3. Classes & Inheritance

Dart OOP Features

Dart supports classes, constructors (named, factory), getters/setters, inheritance, abstract classes, and mixins. Named constructors are common for creating objects from different sources.

abstract class Shape {
  String get name;
  double get area;
  void describe() => print('$name with area ${area.toStringAsFixed(2)}');
}

class Circle extends Shape {
  final double radius;
  Circle(this.radius);

  @override
  String get name => 'Circle';

  @override
  double get area => 3.14159 * radius * radius;
}

class Rectangle extends Shape {
  final double width, height;
  Rectangle(this.width, this.height);

  // Named constructor
  Rectangle.square(double side) : width = side, height = side;

  @override
  String get name => 'Rectangle';

  @override
  double get area => width * height;
}

// Mixin
mixin Colorable {
  String color = 'transparent';
  void setColor(String c) => color = c;
  void printColor() => print('Color: $color');
}

class ColoredCircle extends Circle with Colorable {
  ColoredCircle(super.radius);
}

void main() {
  var shapes = <Shape>[
    Circle(5),
    Rectangle(10, 4),
    Rectangle.square(6),
  ];
  for (var s in shapes) s.describe();

  var cc = ColoredCircle(3);
  cc.setColor('red');
  cc.printColor();
}

4. Async & Futures

Futures, async/await, and Streams

Dart's async model uses Futures for single async values and Streams for sequences of async values. The async/await syntax makes asynchronous code read like synchronous code.

import 'dart:async';

// Future — single async value
Future<String> fetchUsername(int id) async {
  await Future.delayed(Duration(seconds: 1)); // simulate network
  return 'user_$id';
}

// Chaining futures
Future<void> loadUserData() async {
  try {
    final username = await fetchUsername(42);
    print('Loaded: $username');

    // Multiple concurrent futures
    final results = await Future.wait([
      fetchUsername(1),
      fetchUsername(2),
      fetchUsername(3),
    ]);
    print('All users: $results');

  } catch (e) {
    print('Error: $e');
  }
}

// Stream — multiple async values over time
Stream<int> countUp(int max) async* {
  for (var i = 1; i <= max; i++) {
    await Future.delayed(Duration(milliseconds: 100));
    yield i;
  }
}

Future<void> main() async {
  await loadUserData();

  // Listen to a stream
  await for (final value in countUp(5)) {
    print('Tick: $value');
  }

  // StreamController
  final controller = StreamController<String>();
  controller.stream.listen((event) => print('Event: $event'));
  controller.add('hello');
  controller.add('world');
  await controller.close();
}

5. Flutter Widgets

Building UI with Flutter Widgets

In Flutter, everything is a widget. StatelessWidget renders fixed UI. StatefulWidget manages dynamic state. Widgets compose into a widget tree.

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 Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const CounterPage(),
    );
  }
}

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});
  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: $_count', style: Theme.of(context).textTheme.headlineMedium),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                FloatingActionButton(
                  onPressed: () => setState(() => _count--),
                  child: const Icon(Icons.remove),
                ),
                const SizedBox(width: 20),
                FloatingActionButton(
                  onPressed: () => setState(() => _count++),
                  child: const Icon(Icons.add),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

6. State Management

Provider State Management

Provider is a popular Flutter state management solution. It uses ChangeNotifier to notify widgets of state changes, keeping UI in sync with your data model.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// ChangeNotifier model
class CartModel extends ChangeNotifier {
  final List<String> _items = [];

  List<String> get items => List.unmodifiable(_items);
  int get itemCount => _items.length;
  bool get isEmpty => _items.isEmpty;

  void addItem(String item) {
    _items.add(item);
    notifyListeners(); // rebuild dependent widgets
  }

  void removeItem(String item) {
    _items.remove(item);
    notifyListeners();
  }

  void clear() {
    _items.clear();
    notifyListeners();
  }
}

// Provide at root
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => CartModel(),
      child: MaterialApp(home: ShopPage()),
    );
  }
}

// Consume in widget
class CartBadge extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final cart = context.watch<CartModel>();
    return Badge(
      label: Text('${cart.itemCount}'),
      child: const Icon(Icons.shopping_cart),
    );
  }
}

Build Anything with Dart & Flutter!

Dart and Flutter give you the power to build beautiful, performant apps for every platform from a single codebase. The ecosystem is growing fast — now is the perfect time to start.

Happy Coding with Dart!