Flutter Fundamentals
Widget tree, StatelessWidget, StatefulWidget, BuildContext
- 01
What is Flutter and how does it differ from other cross-platform frameworks?
EasyFlutter is Google's UI toolkit for building natively compiled apps for mobile, web and desktop from a single Dart codebase.
// Everything in Flutter is a widget composed together import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { … - 02
What is the difference between StatelessWidget and StatefulWidget?
EasyStatelessWidget— immutable description of UI.// StatelessWidget — pure function of its inputs class GreetingCard extends StatelessWidget { final String name; final Color color; const GreetingCard({super.key, required this.name, this.color = Colors.blue}); … - 03
What is BuildContext and why is it important?
MediumBuildContext is a handle to a widget's location in the widget tree.
class MyWidget extends StatefulWidget { const MyWidget({super.key}); @override State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { … - 04
In what order do a State object's lifecycle methods run, from creation to disposal?
MediumA StatelessWidget has only a constructor and
build(), while a StatefulWidget's State walks a full lifecycle fromcreateStatetodispose.class RichLifecycleWidget extends StatefulWidget { final String config; const RichLifecycleWidget({super.key, required this.config}); @override State<RichLifecycleWidget> createState() => _State(); } … - 05
What is the difference between hot reload, hot restart, and full restart?
EasyHot reload injects new code and keeps app state, hot restart resets the Dart VM and all state, and a full restart rebuilds and reinstalls the app.
class _CounterState extends State<Counter> { int _count = 0; // survives hot reload, reset by hot restart @override void initState() { super.initState(); … - 06
What is MediaQuery and how do you build responsive layouts?
MediumMediaQuery provides information about the device screen: size, pixel ratio, text scale, padding (safe area), orientation, and accessibility settings.
class ResponsivePage extends StatelessWidget { const ResponsivePage({super.key}); @override Widget build(BuildContext context) { // Screen information … - 07
Explain Keys in Flutter and when they are necessary.
MediumKeys give Flutter a stable identity for a widget so that its Element and State survive being reordered or moved.
// ── Problem: Without keys ────────────────── class StatefulTile extends StatefulWidget { final String title; const StatefulTile(this.title, {super.key}); @override State<StatefulTile> createState() => _StatefulTileState(); … - 08
How do you theme a Flutter app and support light and dark mode?
MediumAn app's whole look comes from the ThemeData you hand to MaterialApp, and dark mode is a second ThemeData plus a themeMode.
final _seed = const Color(0xFF6750A4); final lightTheme = ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: _seed), appBarTheme: const AppBarTheme(centerTitle: true), ); … - 09
How does your app find out that it went to the background, and what should you do there?
MediumA State that mixes in WidgetsBindingObserver gets
didChangeAppLifecycleStateevery time the app moves between foreground and background.class _PlayerState extends State<Player> with WidgetsBindingObserver { late final VideoController _controller; @override void initState() { super.initState(); … - 10
What do MaterialApp and Scaffold actually provide, and what breaks without them?
EasyMaterialApp sits once at the root and supplies app-wide machinery, while a Scaffold lays out a single screen.
void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override … - 11
A screen fires its API request from inside build() and hammers the server. Why does build run so often, and where does the call belong?
MediumFlutter treats build as a pure function of the widget's inputs and calls it again every time one of them changes, so anything with a side effect must live outside it.
// ❌ a new request on every rebuild @override Widget build(BuildContext context) { return FutureBuilder( future: api.loadUser(widget.id), // rebuilt = refetched builder: (context, snap) => UserView(snap.data), … - 12
Should a long build method be split into private
_buildHeader()helpers or into separate widget classes?MediumA helper method builds into the parent's own element, so its output rebuilds every time the parent does and can never be skipped.
// ❌ helper method — one Element, rebuilt with the whole page class ProfilePage extends StatelessWidget { const ProfilePage({super.key}); @override Widget build(BuildContext context) => Column( … - 13
A counter is kept as a field on the StatefulWidget itself and setState updates it, but the number keeps resetting. Why?
EasyThe widget object holding that field is thrown away and recreated every time the parent builds; only the State survives, so mutable data has to live there.
// ❌ state on the widget — the field dies with the instance class Counter extends StatefulWidget { // analyzer: must_be_immutable Counter({super.key}); int count = 0; // recreated by every parent build @override … - 14
Why does Flutter make padding, alignment and opacity separate widgets instead of properties that every widget has?
EasyBecause composition keeps the framework small: each widget does one job, and the layout you need comes from nesting them rather than from an ever-growing parameter list on everything.
// Composition: one job per wrapper, and the nesting *is* the layout class PriceTag extends StatelessWidget { const PriceTag({super.key, required this.label}); final String label; @override … - 15
The mobile builds are fine but the web build fails on
Platform.isIOS— how should a Flutter app branch on platform?EasyPlatformcomes fromdart:io, which does not exist on the web, so the import alone breaks the build; Flutter's own answer iskIsWebanddefaultTargetPlatformfrompackage:flutter/foundation.dart.// ❌ the web build fails on the import alone, before any code runs // import 'dart:io' show Platform; // final isApple = Platform.isIOS || Platform.isMacOS; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; … - 16
The keyboard covers the very field the user is typing in — which MediaQuery values describe that, and what actually fixes it?
MediumThe keyboard shows up as
MediaQuery.viewInsetsOf(context).bottom, the part of the window the system has covered, and the fix is to hand that space to a scrollable rather than hard-coding heights.// A bottom sheet has no Scaffold to resize it — pad by the keyboard yourself void showCommentSheet(BuildContext context) { showModalBottomSheet<void>( context: context, isScrollControlled: true, // otherwise the sheet is capped near half-screen builder: (context) => Padding( … - 17
QA reports overlapping text and overflow stripes only on devices with the largest system font — how do you handle text scaling?
MediumThe OS font-size setting scales every
TextthroughMediaQuery.textScalerOf(context), so any box with a hard-coded height and any row of long labels breaks somewhere between 150% and 200%.// Cap scaling once, at the root — generously, and never at 1.0 final app = MaterialApp( builder: (context, child) { final scaler = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 1.4); return MediaQuery( data: MediaQuery.of(context).copyWith(textScaler: scaler), … - 18
You push a details screen and the list behind it keeps polling the API — what happened to that screen's State when the new route covered it?
MediumNothing was disposed:
Navigatorkeeps the covered route in theOverlay, so its State stays alive withdisposeunrun — only its tickers are muted and its render subtree is skipped.import 'dart:async'; import 'package:flutter/material.dart'; // Registered once, on the app final routeObserver = RouteObserver<ModalRoute<void>>(); … - 19
Testers say the app returns to a blank form after sitting in the background for a while on Android — what does Flutter offer for that?
MediumAndroid killed the process while it was backgrounded and Flutter relaunched from
main(); the built-in answer is the state restoration framework, which parks small pieces of UI state with the OS and hands them back on relaunch.import 'package:flutter/material.dart'; // Nothing below is restored without this scope on the app final app = MaterialApp( restorationScopeId: 'app', home: const Cart(), … - 20
Product wants the app in Spanish next sprint and every string is hardcoded in the widgets — what does Flutter give you natively for that?
MediumFlutter's own path is
flutter_localizationsplus thegen-l10ngenerator: strings live in ARB files, the tool generates anAppLocalizationsclass, and widgets read it out of the tree withAppLocalizations.of(context).// l10n.yaml at the project root // arb-dir: lib/l10n // template-arb-file: app_en.arb // output-localization-file: app_localizations.dart // lib/l10n/app_en.arb — ICU plurals live in the data, not in Dart …