What is Flutter?
Flutter is Google's open-source framework for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase. Think of it as a magical paintbrush that lets you draw once and create masterpieces on multiple canvases - iOS, Android, web, Windows, Mac, and Linux.
Unlike other frameworks that translate your code to native components, Flutter draws everything itself using its own rendering engine. It's like building with your own custom LEGO factory instead of using someone else's blocks - you have complete control over how everything looks and behaves.
Why Choose Flutter?
- Stunning UI: Pixel-perfect designs that look identical on all devices
- Fast Performance: Compiles to native code, runs at 60fps consistently
- Hot Reload: See changes instantly (in milliseconds) without losing app state
- Single Codebase: Write once, deploy to iOS, Android, web, desktop
- Rich Widgets: Thousands of customizable, beautiful pre-built components
- Growing Ecosystem: Strong backing from Google, active community
- Declarative UI: Easy to understand and maintain code structure
- Great Documentation: Comprehensive guides and examples
When to Choose Flutter?
Perfect For:
- Apps requiring beautiful, custom UI designs
- Startups needing fast MVP development across platforms
- Apps with lots of animations and complex UI
- When you need web + mobile from same code
- E-commerce apps with rich product displays
- Apps requiring consistent brand experience everywhere
- When performance and smooth animations are critical
Consider React Native Instead When:
- Your team already has strong JavaScript/React expertise
- You need access to more third-party native libraries
- You want to share code with existing React web apps
Flutter vs React Native
| Aspect | Flutter | React Native |
|---|---|---|
| Language | Dart (easier to learn) | JavaScript (more popular) |
| Performance | Slightly better (native code) | Very good (native components) |
| UI Consistency | Perfect (draws own UI) | Good (uses native widgets) |
| Community | Growing rapidly | Larger, more mature |
| Learning Curve | Moderate (new language) | Easy (if you know JS) |
| Hot Reload | Faster, preserves state | Good |
Dart Basics
Dart is the programming language used by Flutter. It's designed to be easy to learn, especially if you know JavaScript, Java, or C#. Think of Dart as a modern, clean language built specifically for building user interfaces.
// Variables and Types
void main() {
// Dart can infer types (var) or you can be explicit
var name = 'John'; // String (inferred)
String city = 'New York'; // String (explicit)
int age = 25; // Integer
double price = 99.99; // Decimal number
bool isActive = true; // Boolean
// Lists (Arrays)
List<String> fruits = ['Apple', 'Banana', 'Orange'];
fruits.add('Mango');
// Maps (Objects/Dictionaries)
Map<String, dynamic> user = {
'name': 'Alice',
'age': 30,
'email': 'alice@example.com'
};
// Null safety (prevent crashes)
String? nullableName; // Can be null
String definitelyName = 'Bob'; // Cannot be null
print('Hello, $name!'); // String interpolation
}
// Functions
int addNumbers(int a, int b) {
return a + b;
}
// Arrow functions (short syntax)
int multiply(int a, int b) => a * b;
// Classes
class Person {
String name;
int age;
// Constructor
Person(this.name, this.age);
// Method
void sayHello() {
print('Hello, I am $name, $age years old');
}
}
// Using the class
var person = Person('Emma', 28);
person.sayHello();
Understanding Widgets
In Flutter, everything is a widget. Widgets are like building blocks - text, buttons, layouts, colors, everything. Think of widgets as LEGO pieces that snap together to build your app's interface.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First Flutter App'),
backgroundColor: Colors.blue,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Text widget
Text(
'Welcome to Flutter!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 20), // Spacing
// Image widget
Image.network(
'https://flutter.dev/images/flutter-logo.png',
width: 100,
height: 100,
),
SizedBox(height: 20),
// Button widget
ElevatedButton(
onPressed: () {
print('Button clicked!');
},
child: Text('Click Me'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
padding: EdgeInsets.symmetric(
horizontal: 30,
vertical: 15,
),
),
),
],
),
),
),
);
}
}
Common Widget Types:
- Layout Widgets: Container, Column, Row, Stack (organize other widgets)
- Display Widgets: Text, Image, Icon (show content)
- Interactive Widgets: Button, TextField, Checkbox (user input)
- Scrolling Widgets: ListView, GridView (long content)
State Management
State is data that can change over time. When state changes, Flutter rebuilds the widget to show the new data. Think of it like a light switch - the switch remembers if it's ON or OFF (state) and shows the appropriate light.
import 'package:flutter/material.dart';
// StatefulWidget = Widget that can change
class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
// This is the state - it can change
int counter = 0;
// Function to update state
void incrementCounter() {
setState(() {
// setState tells Flutter to rebuild the widget
counter++;
});
}
void resetCounter() {
setState(() {
counter = 0;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'You clicked the button:',
style: TextStyle(fontSize: 20),
),
Text(
'$counter',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: incrementCounter,
child: Text('Add One'),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: resetCounter,
child: Text('Reset'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
),
],
),
],
),
),
);
}
}
State Management Options:
- setState: Simple, for local widget state (perfect for beginners)
- Provider: Share state across multiple widgets (recommended by Flutter team)
- Riverpod: Modern, type-safe state management
- Bloc: Pattern for complex apps with predictable state
- GetX: Simple and powerful, includes routing and dependency injection
Material Design
Material Design is Google's design system that makes apps look modern and beautiful. Flutter has built-in Material Design widgets that follow these guidelines automatically.
import 'package:flutter/material.dart';
class MaterialDesignExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// Theme defines colors and styles for entire app
theme: ThemeData(
primarySwatch: Colors.indigo,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true, // Latest Material Design
),
home: Scaffold(
// AppBar at top
appBar: AppBar(
title: Text('Material Design'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {},
),
],
),
// Main content
body: ListView(
padding: EdgeInsets.all(16),
children: [
// Card with elevation (shadow)
Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Beautiful Card',
style: Theme.of(context).textTheme.headlineSmall,
),
SizedBox(height: 8),
Text(
'Material Design makes UI consistent and beautiful',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
SizedBox(height: 16),
// Chips
Wrap(
spacing: 8,
children: [
Chip(
label: Text('Flutter'),
avatar: Icon(Icons.code, size: 18),
),
Chip(
label: Text('Material'),
avatar: Icon(Icons.design_services, size: 18),
),
],
),
],
),
// Floating Action Button
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
// Bottom Navigation Bar
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
),
),
);
}
}
Navigation and Routing
Navigation lets users move between different screens in your app. Think of it like flipping pages in a book or switching channels on TV.
import 'package:flutter/material.dart';
// First Screen
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: ElevatedButton(
// Navigate to details screen
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsScreen(
title: 'Flutter is Awesome!',
),
),
);
},
child: Text('Go to Details'),
),
),
);
}
}
// Second Screen
class DetailsScreen extends StatelessWidget {
final String title;
DetailsScreen({required this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Details')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
title,
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
// Go back to previous screen
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
),
],
),
),
);
}
}
Forms and User Input
Forms are how users input data into your app. Flutter makes form validation and data collection easy.
class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
String email = '';
String password = '';
void _submitForm() {
// Validate form
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
print('Email: $email, Password: $password');
// Send to backend
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter email';
}
if (!value.contains('@')) {
return 'Please enter valid email';
}
return null;
},
onSaved: (value) => email = value!,
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter password';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
},
onSaved: (value) => password = value!,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _submitForm,
child: Text('Login'),
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50),
),
),
],
),
),
),
);
}
}
Fetching Data from APIs
Most apps need to get data from the internet. Flutter uses the http package for this:
import 'package:http/http.dart' as http;
import 'dart:convert';
class UserList extends StatefulWidget {
@override
_UserListState createState() => _UserListState();
}
class _UserListState extends State<UserList> {
List users = [];
bool isLoading = true;
@override
void initState() {
super.initState();
fetchUsers();
}
Future<void> fetchUsers() async {
try {
final response = await http.get(
Uri.parse('https://api.example.com/users'),
);
if (response.statusCode == 200) {
setState(() {
users = json.decode(response.body);
isLoading = false;
});
}
} catch (e) {
print('Error: $e');
setState(() => isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: isLoading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
leading: CircleAvatar(
child: Text(user['name'][0]),
),
title: Text(user['name']),
subtitle: Text(user['email']),
);
},
),
);
}
}
Best Practices
- Use const Widgets: Makes app faster by reusing widgets
- Extract Widgets: Break large widgets into smaller, reusable pieces
- Handle Loading States: Always show progress indicators during data fetching
- Proper Error Handling: Use try-catch for async operations
- Follow Flutter Style Guide: Use linting for clean code
- Use ListView.builder: For long lists, not Column with lots of children
- Test on Real Devices: Emulators don't show real performance
- Optimize Images: Use cached network images, proper sizing
- Use Keys Wisely: For lists that change, use unique keys
- Keep Build Methods Pure: No side effects in build methods
Getting Started
Create your first Flutter app in minutes:
# Install Flutter SDK (download from flutter.dev)
# Add Flutter to PATH
# Check installation
flutter doctor
# Create new project
flutter create my_first_app
# Navigate to project
cd my_first_app
# Run on connected device or emulator
flutter run
# For web
flutter run -d chrome
# Hot reload: Press 'r' in terminal
# Hot restart: Press 'R' in terminal
Ready to Build Beautiful Apps?
Master Flutter and create stunning cross-platform applications
Explore Hybrid Mobile App Course