Flutter in 30 Minutes

What Is Flutter?

Flutter is Google's open-source UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase. It uses the Dart programming language and renders every pixel itself rather than wrapping native platform controls.

Three things make Flutter distinctive:

  1. Declarative UI — You describe what the screen should look like, and Flutter figures out how to update it efficiently.
  2. Hot Reload — Change your code and see the result in under a second, without losing app state.
  3. One codebase, many platforms — iOS, Android, web, Windows, macOS, and Linux from the same Dart source files.

Dart in Five Minutes

Dart is a strongly typed, object-oriented language. If you know Java, JavaScript, or Kotlin, Dart will feel familiar.

Variables and Types

String name = 'Flutter';       // Explicit type
var count = 42;                // Inferred as int
final createdAt = DateTime.now();  // Set once at runtime
const pi = 3.14159;           // Compile-time constant

Functions

int add(int a, int b) => a + b;

String greet({required String name, String title = 'friend'}) {
  return 'Hello, $title $name!';
}

Classes

class Dog {
  final String name;
  int age;

  Dog(this.name, this.age);

  void bark() => print('$name says woof!');
}

Async / Await

Future<String> fetchUser() async {
  final response = await http.get(Uri.parse('https://api.example.com/user'));
  return response.body;
}

Null Safety

Dart enforces null safety. A variable cannot be null unless you explicitly allow it.

String name = 'Alice';    // Cannot be null
String? nickname;          // Can be null
print(nickname?.length);   // Safe access — returns null if nickname is null
print(nickname!.length);   // Force unwrap — crashes if null

The Widget Tree

Everything in Flutter is a widget. Widgets are small, composable building blocks that nest inside each other to form a widget tree.

MaterialApp(
  home: Scaffold(
    appBar: AppBar(title: Text('My App')),
    body: Center(
      child: Text('Hello, Flutter!'),
    ),
  ),
)

This tree is: - MaterialApp contains Scaffold - Scaffold contains AppBar and Center - Center contains Text

When something changes, Flutter compares the new tree to the old one and only repaints what is different. This is why Flutter is fast.

StatelessWidget vs StatefulWidget

StatelessWidget — No mutable state

Use when the widget's output depends only on its constructor arguments.

class Greeting extends StatelessWidget {
  final String name;
  const Greeting({required this.name});

  @override
  Widget build(BuildContext context) {
    return Text('Hello, $name!');
  }
}

StatefulWidget — Has mutable state

Use when the widget needs to change over time (counters, toggles, form input).

class Counter extends StatefulWidget {
  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Count: $_count'),
        ElevatedButton(
          onPressed: () => setState(() => _count++),
          child: Text('Increment'),
        ),
      ],
    );
  }
}

The key rule: call setState() whenever you change state, so Flutter knows to rebuild.

Layout Essentials

Flutter uses three core layout widgets for most screens:

Row (horizontal) and Column (vertical)

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Icon(Icons.star),
    Icon(Icons.star),
    Icon(Icons.star),
  ],
)

Stack (layered)

Stack(
  children: [
    Image.asset('background.png'),
    Positioned(bottom: 16, right: 16, child: Text('Overlay')),
  ],
)

Expanded and Flexible

These tell a Row or Column how to divide available space.

Row(
  children: [
    Expanded(flex: 2, child: Container(color: Colors.red)),
    Expanded(flex: 1, child: Container(color: Colors.blue)),
  ],
)

Lists and Scrolling

For a few items, use ListView directly. For many items, use ListView.builder — it only builds the items currently visible on screen.

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index].name),
      subtitle: Text(items[index].description),
      onTap: () => navigateToDetail(items[index]),
    );
  },
)

Flutter uses a Navigator to manage a stack of screens (routes).

// Push a new screen onto the stack
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => DetailScreen(item: item)),
);

// Pop back to the previous screen
Navigator.pop(context);

For larger apps, consider a routing package like GoRouter that uses URL-based paths.

User Input and Forms

final _controller = TextEditingController();

TextField(
  controller: _controller,
  decoration: InputDecoration(
    labelText: 'Email',
    border: OutlineInputBorder(),
  ),
)

For validated forms, wrap fields in a Form widget with a GlobalKey<FormState>:

final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: TextFormField(
    validator: (value) => value!.isEmpty ? 'Required' : null,
  ),
)

// Validate on submit
if (_formKey.currentState!.validate()) { /* proceed */ }

State Management

For small apps, setState is fine. As your app grows, you will want a dedicated state management approach.

Provider is the most common starting point:

// 1. Define a model
class CartModel extends ChangeNotifier {
  final List<Item> _items = [];
  List<Item> get items => _items;

  void add(Item item) {
    _items.add(item);
    notifyListeners();  // Tell listeners to rebuild
  }
}

// 2. Provide it near the top of the tree
ChangeNotifierProvider(create: (_) => CartModel(), child: MyApp())

// 3. Consume it in any descendant widget
final cart = context.watch<CartModel>();
Text('Items: ${cart.items.length}')

Other popular options include Riverpod, Bloc, and GetX.

HTTP and APIs

Use the http package to fetch data from REST APIs.

import 'package:http/http.dart' as http;
import 'dart:convert';

Future<List<Post>> fetchPosts() async {
  final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
  if (response.statusCode == 200) {
    final List data = jsonDecode(response.body);
    return data.map((json) => Post.fromJson(json)).toList();
  }
  throw Exception('Failed to load posts');
}

Display async data with FutureBuilder:

FutureBuilder<List<Post>>(
  future: fetchPosts(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }
    if (snapshot.hasError) return Text('Error: ${snapshot.error}');
    return ListView.builder(
      itemCount: snapshot.data!.length,
      itemBuilder: (_, i) => ListTile(title: Text(snapshot.data![i].title)),
    );
  },
)

Theming and Styling

Define a consistent look with ThemeData:

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
    textTheme: TextTheme(
      headlineLarge: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
    ),
  ),
)

Access theme values anywhere:

final colors = Theme.of(context).colorScheme;
Container(color: colors.primaryContainer)

Testing

Flutter has three levels of testing:

  1. Unit tests — Pure Dart logic, no widgets.
  2. Widget tests — Build and interact with widgets in a test harness.
  3. Integration tests — Run the full app on a device or emulator.
// Widget test example
testWidgets('Counter increments', (tester) async {
  await tester.pumpWidget(MyApp());

  expect(find.text('0'), findsOneWidget);

  await tester.tap(find.byIcon(Icons.add));
  await tester.pump();

  expect(find.text('1'), findsOneWidget);
});

Where to Go from Here

This crash course covers the highlights. The full course goes deep on each topic across 20 modules:

Modules Focus
0-4 Dart language + widget fundamentals
5-9 Layout, interaction, lists, forms
10-14 Navigation, theming, state, APIs, storage
15-19 Custom widgets, animations, packages, testing, capstone

Start with Module 0: What Is Flutter and work through the foundations. Each module builds on the previous one, with hands-on exercises and a capstone project at the end.

1 / 1