Flutter Basics
Flutter Basics
Flutter is a UI toolkit from Google that targets mobile, web, and desktop from a single codebase. Its own rendering engine, the Dart language, and the widget tree as an expression model are the core. This post covers Flutter's origins, the Dart language, the widget model, the rendering engines (Skia, Impeller), the build tooling, and the package ecosystem.
1. Flutter's origins
| Event | Time |
|---|---|
| Early demo known as "Sky" | 2015 |
| Flutter alpha (Sky renamed to Flutter) | 2017 |
| Flutter 1.0 GA | 2018-12 |
| Flutter 2.0 (web stable, null safety) | 2021-03 |
| Flutter 3.0 (macOS, Linux stable) | 2022-05 |
| Impeller renderer (iOS) default | 3.10 (2023) ~ 3.13 |
Designed from the start with "one engine, every platform" as the goal. Instead of calling platform widgets, it draws every pixel through its own renderer.
2. Dart language
| Event | Time |
|---|---|
| Dart announced (Google) | 2011 |
| Dart 1.0 | 2013 |
| Dart 2.0 (strong typing) | 2018 |
| sound null safety (opt-in) | 2.12 (2021) |
| Dart 3.0 (sound null safety enforced, pattern matching, etc.) | 2023-05 |
Dart began as a JavaScript alternative, but after Flutter adopted it, it found its place as a client UI language.
Characteristics:
- C-family syntax, familiar to Java / JavaScript / TypeScript.
- Both AOT (Ahead-Of-Time) and JIT (Just-In-Time) — JIT during development (hot reload), AOT for release (performance).
- sound null safety — a variable's nullability is expressed in the type system.
- Pattern matching, records, sealed classes (3.0+).
String greet(String? name) {
return switch (name) {
null => 'hello, friend',
String s when s.isEmpty => 'hello, friend',
String s => 'hello, $s',
};
}
3. Widget tree
Flutter's expression model is the widget tree. The whole screen is built from widgets, and a widget's build output is again widgets:
class HelloApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Hello')),
body: Center(child: Text('world')),
),
);
}
}
| Kind | Meaning |
|---|---|
| StatelessWidget | Same input, same output. No internal state. |
| StatefulWidget | Has its own state. The State object lives along the widget lifecycle. |
class Counter extends StatefulWidget {
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => count++),
child: Text('$count'),
);
}
}
When setState is called, the corresponding subtree rebuilds.
4. Widget · Element · RenderObject
Flutter internally uses three trees:
- Widget Tree — lightweight configuration objects. Recreated frequently.
- Element Tree — instances of widgets. They have a lifecycle and keep the mapping with the child tree.
- RenderObject Tree — performs the actual layout and painting.
This separation keeps the cost of recreating widget objects low. Diffing happens in the element tree.
5. Rendering engines
Skia — Flutter started on Skia (the 2D graphics engine used by Chrome and Android). It can use both CPU and GPU, but Flutter mainly uses the GPU path.
Impeller — first-frame jank on iOS was reported often. One cause was Skia's shaders compiling on first appearance on screen. Impeller is a new renderer designed to fix this by precompiling shaders at build time:
- iOS — default in 3.10 (2023).
- Android — gradual enablement (defaulted on in stages between 3.16 and 3.27).
- macOS · Web · Desktop — work in progress.
6. Development flow
| Action | Meaning |
|---|---|
| Hot Reload | Inject only changed code. Widget tree is preserved, state too. |
| Hot Restart | Restart the app. State is reset. |
Hot Reload is what Dart's JIT enables. It shines when iterating quickly on UI details.
Build tools:
flutter create app— create a project.flutter run— run on a device or emulator.flutter build apk|ipa|web|windows|macos|linux— per-platform artefact.flutter pub get— fetch packages.flutter pub upgrade— update.dart format·flutter analyze— format · lint.
The Mac · Linux and Windows commands are identical.
7. pub.dev and packages
The official Dart · Flutter package registry. Its scoring system (pikes) evaluates maintenance, platform compatibility, and documentation.
| Category | Packages |
|---|---|
| State management | provider · riverpod · bloc · get_it |
| Routing | go_router · auto_route |
| HTTP | dio · http |
| Local DB | sqflite · drift · isar · hive |
| Serialization | json_serializable · freezed |
| Local storage | shared_preferences · flutter_secure_storage |
| Push | firebase_messaging |
8. State management
Flutter itself only ships setState and InheritedWidget. Larger apps reach for external state-management packages:
- Provider — started as the official recommendation. Simple.
- Riverpod — the successor to Provider. Compile-time safety.
- Bloc / Cubit — event → state flow. Strong on testability.
- GetX — bundles dependencies, routing, and state. Simplicity is a strength; structural enforcement is a weakness.
- MobX — a reactive model.
The choice depends on team familiarity and app size.
9. Platform channels · adaptive UI
Platform channels — when calling native code, use MethodChannel, EventChannel, BasicMessageChannel. iOS in Swift / Obj-C, Android in Kotlin / Java.
Adaptive UI — Cupertino widgets for iOS and Material widgets for Android come from separate libraries. Branch on Platform.isIOS or use abstraction packages like flutter_platform_widgets.
10. Common pitfalls
Bundle size — Hello World runs into several MB. Including its own engine is the cause. Text compression and code splitting aren't as flexible as they are on the regular web.
iOS first-frame jank — a common report before Impeller. Improved since, but spots with many custom shaders still need checking.
Missing platform widgets — new iOS · Android UI controls don't arrive instantly. Flutter has to catch up.
Accessibility tree — because it draws on its own, OS accessibility needs separate mapping. Missing labels make screen readers unreliable.
Web target limits — Flutter Web uses Skia (canvaskit) or HTML backends. Weaker than regular web frameworks for SEO indexing, accessibility, and bundle size.
State-management splintering — too many choices raise the decision cost. A team convention helps.
Dart package diversity — not as broad as Node or Python. Some areas need direct implementation.
OS-update compatibility — yearly SDK changes break some packages. Check library maintenance activity.
Closing thoughts
Flutter brings pixel-level consistency through its own-canvas model. Dart's sound null safety, pattern matching, and AOT / JIT support form the foundation. Limits include bundle size, keeping up with platform widgets, accessibility mapping, and weak web targets. It fits best where 60 / 120 fps animations matter or consistent pixels are part of the business value.
Next
- android-build-apk
- ios-build
Flutter official docs · Dart official docs · Flutter Codelabs · pub.dev · Impeller intro · Flutter Engine GitHub · Effective Dart · Flutter Samples for reference.