🏠 Home / Hub

Flutter 01 — Setup & Dart Basics

Get Flutter installed, learn Dart fundamentals, and write your first Flutter app from scratch.

1. What is Flutter?

Flutter is Google's open-source UI framework for building natively compiled applications from a single Dart codebase. One codebase targets all platforms:

PlatformOutputNotes
AndroidAPK / AABAndroid 5.0 (API 21) and above
iOSIPARequires macOS and Xcode to build
WebHTML / JS / WASMCanvasKit or HTML renderer
Windows.exeStable since Flutter 3.0
macOS.appStable since Flutter 3.0
LinuxBinaryStable since Flutter 3.0

Flutter renders via its own Skia / Impeller engine — no WebView, no native UI widgets called. Every pixel is drawn by Flutter itself, giving pixel-perfect consistency across platforms.

Flutter's superpower: one codebase, all platforms, identical UI. The Dart language compiles to native ARM or x86 machine code, making Flutter apps genuinely fast.

2. Installing Flutter

Windows Installation Steps

  1. Go to flutter.dev/docs/get-started/install
  2. Download the latest stable Flutter SDK ZIP
  3. Extract to C:\flutter (avoid spaces in the path)
  4. Add C:\flutter\bin to your system PATH environment variable
  5. Open a new terminal and run flutter doctor
# Check Flutter installation and environment
flutter doctor

# Verbose output (more details for troubleshooting)
flutter doctor -v

# Accept Android SDK licenses
flutter doctor --android-licenses

# Upgrade Flutter to latest stable
flutter upgrade

# Switch to a specific channel
flutter channel stable

Expected flutter doctor output

[✓] Flutter (Channel stable, 3.x.x, on Windows 11)
[✓] Windows Version (Windows 11)
[✓] Android toolchain - develop for Android devices
    • Android SDK at C:\Users\You\AppData\Local\Android\sdk
    • Platform android-34, build-tools 34.0.0
[✓] Chrome - develop for the web
[✓] Visual Studio - develop Windows apps (Visual Studio 2022)
[✓] VS Code (version 1.90.x)
    • Flutter extension version 3.x.x
[✓] Connected device (3 available)
[✓] Network resources
Fix any [!] or [x] warnings that flutter doctor shows. For Android, install Android Studio, create an emulator, and run flutter doctor --android-licenses to accept licenses.

3. VS Code Setup

VS Code is the recommended lightweight editor for Flutter development. It gives you IntelliSense, hot reload, and widget inspection.

  1. Install Visual Studio Code
  2. Open Extensions panel (Ctrl+Shift+X)
  3. Search and install: Flutter (by Dart Code) — this auto-installs the Dart extension too
  4. Restart VS Code and select a device from the status bar

Key VS Code Shortcuts for Flutter

ShortcutAction
F5Run / Debug app
Ctrl+Shift+P → "Flutter: New Project"Create a new Flutter project
Ctrl+.Quick fix / wrap with widget
r in debug terminalHot reload (preserves state)
R in debug terminalHot restart (resets state)
Alt+Shift+FFormat Dart file
Ctrl+Shift+P → "Dart: Open DevTools"Open Flutter DevTools (widget inspector, performance)

4. Creating & Running Your First Project

# Create a new Flutter project
flutter create my_app

# Navigate into it
cd my_app

# List available devices/emulators
flutter devices

# Run on default device
flutter run

# Run on Chrome (web)
flutter run -d chrome

# Run on Windows desktop
flutter run -d windows

# Build release APK
flutter build apk --release

Project folder structure

my_app/
  android/         -- Android-specific files (gradle, manifests)
  ios/             -- iOS-specific files (Xcode project)
  lib/
    main.dart      -- YOUR APP STARTS HERE (entry point)
  test/
    widget_test.dart
  pubspec.yaml     -- Dependencies and assets (like package.json)
  pubspec.lock     -- Lock file (do not edit manually)
  web/             -- Web-specific files
  windows/         -- Windows-specific files

Minimal main.dart

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: 'My Flutter App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(title: const Text('Hello Flutter')),
        body: const Center(child: Text('Welcome!')),
      ),
    );
  }
}

5. Dart Variables & Types

Dart is a strongly-typed, object-oriented language. Type inference lets you skip writing the type when it can be inferred.

// Type inference — Dart figures out the type
var name    = 'Alice';      // String
var age     = 30;           // int
var price   = 9.99;         // double
var isReady = true;         // bool

// Explicit types (same result, more readable)
String city       = 'Yangon';
int    count      = 100;
double temperature = 36.5;
bool   isDone     = false;

// final — set once at runtime
final createdAt = DateTime.now();   // OK, evaluated at runtime
// createdAt = DateTime.now();       // ERROR — cannot reassign

// const — compile-time constant (must be known at compile time)
const pi      = 3.14159;
const appName = 'MyApp';

// ---- Collections ----

// List (ordered, like an array)
List<String> fruits = ['apple', 'banana', 'mango'];
fruits.add('grape');
fruits.remove('banana');
fruits.insert(0, 'cherry');
print(fruits.length);      // 3
print(fruits[0]);          // cherry
print(fruits.first);       // cherry
print(fruits.last);        // grape
print(fruits.contains('mango'));  // true

// Map (key-value pairs)
Map<String, dynamic> user = {
  'name': 'Bob',
  'age': 25,
  'email': 'bob@example.com',
};
print(user['name']);           // Bob
user['phone'] = '09123456';   // add
user.remove('email');          // remove
print(user.keys.toList());     // [name, age, phone]
print(user.containsKey('age')); // true

// Set (unique values only)
Set<int> ids = {1, 2, 3, 2, 1};
print(ids);   // {1, 2, 3} — duplicates removed
dynamic turns off type checking for a variable. Prefer specific types — dynamic defeats null safety and autocomplete.

6. Dart Null Safety

Dart has sound null safety since Dart 2.12. By default, variables cannot be null. You explicitly opt in to nullability with ?.

// Non-nullable (default) — cannot hold null
String name = 'Alice';
// name = null;   // COMPILE ERROR

// Nullable — add ? to allow null
String? nickname;           // defaults to null
nickname = 'Ali';
nickname = null;            // OK

// Null-aware operators
String? city;

// ?? — null coalescing: use right side if left is null
String display = city ?? 'Unknown City';
print(display);    // Unknown City

// ??= — assign only if currently null
city ??= 'Yangon';          // sets city because it was null
city ??= 'Mandalay';        // does NOT change — already set

// ?. — null-safe member access (returns null if object is null)
String? upper = city?.toUpperCase();   // 'YANGON'
int?    len   = city?.length;          // 6

// ! — force-unwrap (throws Null check error if null — use carefully)
String knownCity = city!;   // asserts non-null

// Late — non-nullable but initialized later (use carefully)
late String token;
// ... after some async work ...
token = 'abc123';
print(token);   // safe to use now

// Null safety in functions
void printLength(String? s) {
  if (s == null) return;
  print(s.length);   // Dart knows s is non-null here (smart cast)
}
Use ?? for defaults, ?. for safe member access, and avoid ! unless you are 100% certain the value is non-null.

7. Dart Functions

// Basic function with return type
int add(int a, int b) {
  return a + b;
}

// Arrow function — for single expressions only
int multiply(int a, int b) => a * b;
String greetDefault(String name) => 'Hello, $name!';

// Optional positional parameters (in square brackets, with default value)
String greet(String name, [String greeting = 'Hello']) {
  return '$greeting, $name!';
}
print(greet('Alice'));           // Hello, Alice!
print(greet('Bob', 'Hi'));       // Hi, Bob!

// Named parameters (in curly braces)
// required means the caller MUST provide the value
void createUser({
  required String name,
  required String email,
  int age = 0,              // optional with default
  bool isAdmin = false,
}) {
  print('$name | $email | age:$age | admin:$isAdmin');
}

createUser(name: 'Alice', email: 'a@b.com');
createUser(name: 'Bob', email: 'b@c.com', age: 30, isAdmin: true);

// Functions as first-class values
var double = (int n) => n * 2;
print(double(5));    // 10

// Passing functions as arguments
void runTwice(Function action) {
  action();
  action();
}
runTwice(() => print('Running!'));

// Higher-order collection methods
List<int> nums = [1, 2, 3, 4, 5];
var doubled = nums.map((n) => n * 2).toList();          // [2,4,6,8,10]
var evens   = nums.where((n) => n.isEven).toList();     // [2, 4]
var sum     = nums.fold(0, (acc, n) => acc + n);        // 15
var any2    = nums.any((n) => n > 4);                   // true
var all2    = nums.every((n) => n > 0);                 // true

// Async / Await
Future<String> fetchData() async {
  await Future.delayed(const Duration(seconds: 1));
  return 'data loaded';
}

// Calling async
void main() async {
  String result = await fetchData();
  print(result);    // data loaded
}

// Stream (continuous async events)
Stream<int> countUp() async* {
  for (int i = 1; i <= 5; i++) {
    await Future.delayed(const Duration(seconds: 1));
    yield i;
  }
}
// Listen: countUp().listen((n) => print(n));

8. Dart Classes

// Basic class
class Person {
  String name;
  int age;

  // Primary constructor using shorthand (this.name sets the field)
  Person(this.name, this.age);

  // Named constructor
  Person.guest() : name = 'Guest', age = 0;

  // Factory constructor — can return cached instance or subtype
  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(json['name'] as String, json['age'] as int);
  }

  // Instance method
  void introduce() {
    print('I am $name, age $age.');
  }

  // Getter (computed property)
  bool get isAdult => age >= 18;

  // Setter
  set fullName(String value) {
    name = value.split(' ').first;
  }

  @override
  String toString() => 'Person($name, $age)';
}

// --- Usage ---
var p1 = Person('Alice', 28);
var p2 = Person.guest();
var p3 = Person.fromJson({'name': 'Bob', 'age': 22});
p1.introduce();         // I am Alice, age 28.
print(p1.isAdult);      // true
print(p2);              // Person(Guest, 0)

// Inheritance
class Employee extends Person {
  String company;

  Employee(String name, int age, this.company) : super(name, age);

  @override
  void introduce() {
    super.introduce();
    print('I work at $company.');
  }
}

// Abstract class — blueprint that cannot be instantiated directly
abstract class Shape {
  double area();    // subclasses must implement this
  double perimeter();
}

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

  @override
  double area() => 3.14159 * radius * radius;

  @override
  double perimeter() => 2 * 3.14159 * radius;
}

// Mixin — add capabilities without full inheritance
mixin CanFly {
  void fly() => print('Flying!');
}

mixin CanSwim {
  void swim() => print('Swimming!');
}

class Duck extends Animal with CanFly, CanSwim {}
// Duck can both fly() and swim()

// Enum
enum Status { pending, active, inactive, deleted }
var s = Status.active;
print(s.name);      // active
In Flutter, almost every UI element is a class. Understanding Dart classes is essential for building custom widgets, data models, and services.

📌 Study Checklist