Master cross-platform mobile app development with Google's Flutter framework
Flutter is an open-source UI software development kit created by Google. It enables developers to build natively compiled applications for mobile (iOS & Android), web, and desktop from a single codebase.
Unlike other cross-platform frameworks that use web views or native widgets, Flutter draws its own widgets using a high-performance rendering engine (Skia). This approach provides:
Write once, run everywhere. Build applications for mobile, web, and desktop from one codebase, reducing development time and maintenance costs.
See changes instantly without losing app state. This feature dramatically speeds up development and makes experimentation easy.
Rich set of customizable widgets following Material Design and Cupertino (iOS) guidelines. Create stunning, brand-focused designs.
Compiled to native ARM code for mobile and to JavaScript for web. No JavaScript bridge overhead like React Native.
Backed by Google with active community support, thousands of packages, and extensive documentation.
Fast development cycles, excellent tooling, and clear documentation help teams ship features quickly.
Flutter's architecture consists of three main layers:
The top layer where developers work. Contains:
Provides low-level rendering using Skia graphics library, text layout, file/network I/O, and plugin architecture.
Coordinates with the underlying operating system for rendering surfaces, accessibility, and input.
Flutter uses Dart, a language optimized for building user interfaces. Key features include:
// Variables
var name = 'Flutter';
String title = 'Developer';
int age = 5;
double version = 3.0;
bool isAwesome = true;
// Functions
String greet(String name) {
return 'Hello, $name!';
}
// Arrow functions
int add(int a, int b) => a + b;
// Classes
class Developer {
String name;
int experience;
Developer(this.name, this.experience);
void code() {
print('$name is coding with $experience years experience');
}
}
// Lists and Maps
List<String> frameworks = ['Flutter', 'React Native', 'Ionic'];
Map<String, int> versions = {'Flutter': 3, 'Dart': 3};
// Null Safety (Dart 2.12+)
String? nullableString; // Can be null
String nonNullString = 'Hello'; // Cannot be null
Everything in Flutter is a widget. Widgets describe what the UI should look like given their current configuration and state.
Immutable widgets that don't maintain any state.
class Greeting extends StatelessWidget {
final String name;
const Greeting({Key? key, required this.name}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text('Hello, $name!');
}
}
Widgets that maintain mutable state that can change over time.
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'),
),
],
);
}
}
Flutter uses a compositional approach to build UIs. Widgets are nested to create complex layouts.
class ProfileCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
),
SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'John Doe',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Text(
'Flutter Developer',
style: TextStyle(color: Colors.grey),
),
],
),
],
),
SizedBox(height: 16),
Text(
'Building beautiful cross-platform applications with Flutter.',
style: TextStyle(fontSize: 14),
),
],
),
);
}
}
Managing state effectively is crucial for building scalable Flutter applications.
Simple state management for small widgets and local state.
setState(() {
_counter++;
});
Google's recommended solution for app-wide state management.
// Model
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Usage in widget
Consumer<CounterModel>(
builder: (context, counter, child) {
return Text('${counter.count}');
},
)
Flutter provides excellent support for HTTP requests and REST APIs.
import 'package:http/http.dart' as http;
import 'dart:convert';
// GET Request
Future<List<Post>> fetchPosts() async {
final response = await http.get(
Uri.parse('https://api.example.com/posts'),
);
if (response.statusCode == 200) {
List<dynamic> jsonData = json.decode(response.body);
return jsonData.map((json) => Post.fromJson(json)).toList();
} else {
throw Exception('Failed to load posts');
}
}
// POST Request
Future<Post> createPost(String title, String body) async {
final response = await http.post(
Uri.parse('https://api.example.com/posts'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'title': title,
'body': body,
}),
);
if (response.statusCode == 201) {
return Post.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to create post');
}
}
FutureBuilder<List<Post>>(
future: fetchPosts(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return PostCard(post: snapshot.data![index]);
},
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return CircularProgressIndicator();
},
)
Flutter offers several options for storing data locally.
import 'package:shared_preferences/shared_preferences.dart';
// Save data
Future<void> saveUserName(String name) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('userName', name);
}
// Read data
Future<String?> getUserName() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('userName');
}
Use the sqflite package for relational database storage.
Fast, lightweight NoSQL database written in pure Dart.
Real-time database and cloud storage solution.
Flutter can access native platform features through platform channels and plugins.
// Camera access
import 'package:camera/camera.dart';
// Location services
import 'package:geolocator/geolocator.dart';
Position position = await Geolocator.getCurrentPosition();
// Notifications
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
// File picker
import 'package:file_picker/file_picker.dart;
Flutter provides comprehensive testing support at unit, widget, and integration levels.
import 'package:test/test.dart';
void main() {
test('Counter increments', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter displays correct value', (WidgetTester 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);
});
}
Test complete app workflows on real devices or emulators.
const widgets to avoid unnecessary rebuildsListView.builder for long lists