Module 4: Flutter & Dart
Build beautiful, natively compiled applications with Flutter and Dart programming language.
What is Flutter?
Flutter is Google's UI toolkit for building natively compiled applications from a single codebase. Think of it as a complete framework that includes everything you need - UI widgets, rendering engine, testing tools, and more. Unlike React Native which uses native components, Flutter draws its own UI.
🚀 Why Flutter?
- Fast Development: Hot reload in milliseconds
- Beautiful UI: Material Design & Cupertino widgets
- Native Performance: Compiled to ARM code
- Single Codebase: iOS, Android, Web, Desktop
- Growing Ecosystem: 30,000+ packages on pub.dev
- Backed by Google: Used in Google Pay, Alibaba
Dart Programming Language
Dart is the language behind Flutter. It's easy to learn, especially if you know JavaScript or Java.
Dart Basics:
// Variables
var name = 'Flutter'; // Type inferred
String title = 'Developer'; // Explicit type
int age = 25;
double price = 99.99;
bool isActive = true;
// Null safety (Dart 2.12+)
String? nullableName; // Can be null
String nonNullName = 'John'; // Cannot be null
// Functions
int add(int a, int b) {
return a + b;
}
// Arrow functions
int multiply(int a, int b) => a * b;
// Classes
class Person {
String name;
int age;
Person(this.name, this.age);
void greet() {
print('Hi, I am $name');
}
}
Dart Features:
- • Sound Null Safety: Prevents null errors at compile time
- • Async/Await: Easy asynchronous programming
- • Collections: List, Set, Map with powerful methods
- • Mixins: Reuse code across multiple classes
- • Extension Methods: Add methods to existing classes
Flutter Widgets
Everything in Flutter is a widget! Widgets are the building blocks of your UI.
Stateless Widget
Immutable, doesn't change over time
class MyWidget extends
StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Hello');
}
}
Stateful Widget
Can change state and rebuild
class Counter extends
StatefulWidget {
@override
_CounterState createState() =>
_CounterState();
}
Common Widgets:
// Layout Widgets
Container() // Box with padding, margin, decoration
Row() // Horizontal layout
Column() // Vertical layout
Stack() // Overlapping widgets
Padding() // Add padding
// UI Widgets
Text('Hello') // Display text
Image.network(url) // Display image
Icon(Icons.home) // Material icon
ElevatedButton() // Material button
TextField() // Text input
// Scrolling
ListView() // Scrollable list
GridView() // Grid layout
SingleChildScrollView() // Scrollable single child
Your First Flutter App
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My First App'),
),
body: Center(
child: Text(
'Hello, Flutter!',
style: TextStyle(fontSize: 24),
),
),
);
}
}
State Management
Managing state is crucial in Flutter apps. Here are the popular approaches:
setState (Built-in)
Simple state management for single widgets.
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
void increment() {
setState(() => count++);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: increment,
child: Text('Increment'),
),
],
);
}
}
Provider (Recommended)
Google's recommended approach for app-wide state.
// 1. Create a ChangeNotifier
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// 2. Provide it
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
)
// 3. Consume it
Consumer<CounterModel> (
builder: (context, counter, child) =>
Text('${ counter.count }'),
)
Riverpod (Modern)
Improved version of Provider with better safety.
final counterProvider = StateProvider((ref) => 0);
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
}
}
Bloc (Enterprise)
Business Logic Component pattern for large apps.
// Events
abstract class CounterEvent {}
class Increment extends CounterEvent {}
// Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
}
}
Navigation & Routing
Basic Navigation:
// Push new screen
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);
// Pop back
Navigator.pop(context);
// Named routes
MaterialApp(
routes: {
'/': (context) => HomeScreen(),
'/details': (context) => DetailsScreen(),
},
);
Navigator.pushNamed(context, '/details');
Platform-Specific Code
Sometimes you need different behavior for iOS and Android.
import 'dart:io' show Platform;
// Check platform
if (Platform.isIOS) {
// iOS-specific code
} else if (Platform.isAndroid) {
// Android-specific code
}
// Platform-specific widgets
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Platform.isIOS
? CupertinoButton(child: Text('iOS'))
: ElevatedButton(child: Text('Android'));
Hot Reload & Development
Development Workflow:
- • Hot Reload (r): Update UI instantly, keeps state
- • Hot Restart (R): Restart app, lose state
- • DevTools: Inspector, performance, network
- • Widget Inspector: Visual debugging tool
- • Flutter Doctor: Check setup issues
Complete Todo App Example
import 'package:flutter/material.dart';
void main() => runApp(TodoApp());
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
theme: ThemeData(primarySwatch: Colors.orange),
home: TodoList(),
);
}
}
class TodoList extends StatefulWidget {
@override
_TodoListState createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
final List<String> _todos = [];
final TextEditingController _controller =
TextEditingController();
void _addTodo() {
if (_controller.text.isNotEmpty) {
setState(() {
_todos.add(_controller.text);
_controller.clear();
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('My Todos')),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter todo',
),
),
),
SizedBox(width: 8),
ElevatedButton(
onPressed: _addTodo,
child: Text('Add'),
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: _todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_todos[index]),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => setState(() {
_todos.removeAt(index);
}),
),
);
},
),
),
],
),
);
}
}
📚 Module Summary
You've mastered Flutter and Dart:
- ✓ Dart programming language basics
- ✓ Flutter widgets and layouts
- ✓ State management (setState, Provider, Riverpod, Bloc)
- ✓ Navigation and routing
- ✓ Platform-specific code
- ✓ Hot reload development workflow
Next: Learn mobile UI/UX design principles!