Flutter Development Complete Guide
Introduction
Flutter is Google's UI toolkit for building natively compiled applications from a single codebase for mobile, web, and desktop. With its reactive framework and rich widget library, Flutter enables fast, beautiful app development.
1. Setup and Installation
# Download Flutter SDK
# https://flutter.dev/docs/get-started/install
# Add to PATH
export PATH="$PATH:`pwd`/flutter/bin"
# Check installation
flutter doctor
# Create new project
flutter create my_app
cd my_app
flutter run
2. Dart Fundamentals
// Variables and types
var name = 'John';
String message = 'Hello';
int age = 30;
double price = 19.99;
bool isActive = true;
List<String> items = ['a', 'b', 'c'];
Map<String, int> scores = {'John': 100};
// Functions
int add(int a, int b) => a + b;
// Optional parameters
void greet(String name, {String? title}) {
print('Hello ${title ?? ''} $name');
}
// Classes
class User {
final String name;
final int age;
User({required this.name, required this.age});
void sayHello() => print('Hi, I\'m $name');
}
// Async/await
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'Data loaded';
}
3. Basic Widgets
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: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Column(
children: [
Text('Hello Flutter',
style: TextStyle(fontSize: 24)
),
ElevatedButton(
onPressed: () => print('Pressed'),
child: Text('Click Me'),
),
Image.network('https://example.com/image.png'),
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Text('Container'),
),
],
),
);
}
}
4. Layouts
// Column & Row
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Item 1'),
Text('Item 2'),
],
)
// Stack (overlapping widgets)
Stack(
children: [
Image.network('background.jpg'),
Positioned(
top: 20,
left: 20,
child: Text('Overlay Text'),
),
],
)
// ListView
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
onTap: () => handleTap(index),
);
},
)
// GridView
GridView.count(
crossAxisCount: 2,
children: List.generate(10, (index) {
return Card(child: Center(child: Text('Item $index')));
}),
)
5. State Management
// StatefulWidget
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 pattern
# pubspec.yaml
dependencies:
provider: ^6.0.0
import 'package:provider/provider.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Usage
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
)
Consumer<CounterModel>(
builder: (context, counter, child) {
return Text('${counter.count}');
},
)
6. Navigation
// Basic navigation
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
Navigator.pop(context);
// Named routes
MaterialApp(
routes: {
'/': (context) => HomeScreen(),
'/details': (context) => DetailsScreen(),
},
)
Navigator.pushNamed(context, '/details', arguments: {'id': 123});
// Get arguments
final args = ModalRoute.of(context)!.settings.arguments as Map;
// Navigator 2.0 (go_router)
# pubspec.yaml
dependencies:
go_router: ^13.0.0
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/details/:id',
builder: (context, state) {
final id = state.pathParameters['id'];
return DetailsScreen(id: id);
},
),
],
);
context.go('/details/123');
7. API Integration
# pubspec.yaml
dependencies:
http: ^1.1.0
import 'package:http/http.dart' as http;
import 'dart:convert';
class ApiService {
static const baseUrl = 'https://api.example.com';
Future<List<User>> getUsers() async {
final response = await http.get(Uri.parse('$baseUrl/users'));
if (response.statusCode == 200) {
List data = json.decode(response.body);
return data.map((json) => User.fromJson(json)).toList();
}
throw Exception('Failed to load users');
}
Future<void> createUser(User user) async {
await http.post(
Uri.parse('$baseUrl/users'),
headers: {'Content-Type': 'application/json'},
body: json.encode(user.toJson()),
);
}
}
// Model with JSON serialization
class User {
final int id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) {
return User(id: json['id'], name: json['name']);
}
Map<String, dynamic> toJson() => {'id': id, 'name': name};
}
8. Local Storage
# pubspec.yaml
dependencies:
shared_preferences: ^2.2.0
sqflite: ^2.3.0
// SharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'john');
final username = prefs.getString('username');
// SQLite
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await initDatabase();
return _database!;
}
Future<Database> initDatabase() async {
return await openDatabase(
'app.db',
version: 1,
onCreate: (db, version) {
return db.execute(
'CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT)',
);
},
);
}
Future<void> insertUser(User user) async {
final db = await database;
await db.insert('users', user.toMap());
}
Future<List<User>> getUsers() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('users');
return List.generate(maps.length, (i) => User.fromMap(maps[i]));
}
}
9. Animations
class AnimatedBox extends StatefulWidget {
@override
_AnimatedBoxState createState() => _AnimatedBoxState();
}
class _AnimatedBoxState extends State<AnimatedBox>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 2),
vsync: this,
);
_animation = Tween<double>(begin: 0, end: 300).animate(_controller);
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.blue,
);
},
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
10. Testing
# pubspec.yaml
dev_dependencies:
flutter_test:
sdk: flutter
// Unit test
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Counter increments', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
// Widget test
testWidgets('Button tap increments counter', (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);
});
💡 Best Practices:
- Use const constructors for immutable widgets
- Keep widget tree shallow for better performance
- Implement proper error handling
- Use DevTools for debugging and profiling
- Follow Material Design or Cupertino guidelines
- Write comprehensive tests
- Use flutter analyze for code quality
Conclusion
Flutter provides a powerful framework for building beautiful, high-performance cross-platform applications. Master these concepts to create professional mobile apps with excellent user experiences.