Theory
A screen made entirely of one noun
Last lesson's minimal app was 4 widgets deep: MaterialApp, Scaffold, Center, Text. Ask Flutter what ANYTHING on screen is: a button, the gap around it, the screen itself: and the answer is always the same noun: a widget.
One noun would be chaos without classification. The syllabus cuts the widget world along 3 clean axes, and between them they answer the only 3 questions that matter when you reach for a widget: does it SHOW? can it CHANGE? how many CHILDREN?
Theory
Axis 1: visible vs invisible
Visible widgets put pixels on screen or take input: Text, Image, Icon, ElevatedButton, TextField: the ones a user would point at.
Invisible widgets draw nothing themselves: they ARRANGE others: Row and Column line children up, Center positions one, Padding pushes space around one, Stack overlaps a pile, Scaffold frames a whole screen (app bar slot, body slot, floating button slot).
A screen is invisible scaffolding holding visible leaves: exactly the XML-layouts-holding-widgets structure of Unit 1, rewritten as Dart objects.
Theory
Axis 2: stateless vs stateful (the exam axis)
StatelessWidget: immutable. Its build() method renders purely from the configuration it was given: same inputs, same pixels, forever. The fest's name label, a poster, a rules page.
StatefulWidget: comes in 2 pieces: the widget plus a State object that survives rebuilds. Mutable data (seats left, a checkbox's tick) lives in the State, and changing it goes through one gate:
setState(() { seats--; });
setState mutates AND tells Flutter to re-run build(), repainting with new values. Forgetting the setState wrapper is Flutter's most classic bug: the data changes, the screen does not.
At a glance
The 3 classifications at a glance
| Axis | Kind A | Kind B |
|---|---|---|
| Pixels | Visible: Text, Image, Button, Icon, TextField | Invisible: Row, Column, Center, Padding, Stack, Scaffold |
| Change | Stateless: immutable, build from config | Stateful: State object + setState() rebuilds |
| Children | Single-child: child: (Center, Padding, Container) | Multi-child: children: [ ] (Row, Column, Stack, ListView) |
Practical
One of each change-kind, side by side
// STATELESS: fixed configuration in, same pixels out, forever
class FestTitle extends StatelessWidget {
const FestTitle({super.key});
@override
Widget build(BuildContext context) {
return const Text('TechnoUtsav 2026');
}
}
// STATEFUL: the seat counter that must change on screen
class SeatCounter extends StatefulWidget {
const SeatCounter({super.key});
@override
State<SeatCounter> createState() => _SeatCounterState();
}
class _SeatCounterState extends State<SeatCounter> {
int seats = 350; // mutable data lives in State
@override
Widget build(BuildContext context) {
return Column( // multi-child, invisible
children: [
Text('Seats left: $seats'), // visible leaf
ElevatedButton(
onPressed: () => setState(() { seats--; }), // the gate
child: const Text('Book one'),
),
],
);
}
}
Quiz
FestConnect Flutter needs a seats-left display that decreases every time Book is tapped. Which widget kind, and why?
- StatelessWidget: the layout of the counter never changes
- StatefulWidget: the displayed value must change over time, so it needs a State object and setState
- An invisible widget: counters do not draw pixels
- Either works: stateless widgets can also update via build()
Show the answer
StatefulWidget: the displayed value must change over time, so it needs a State object and setState
The deciding question is always: must this widget's OUTPUT change while it is on screen? A ticking counter says yes, and changeable data needs a home that survives rebuilds (the State object) plus the setState gate to trigger repainting. Option A confuses layout stability with data stability: the arrangement stays, the NUMBER moves. Option C misfiles the axis entirely: a counter shows text: visible. Option D is the trap with a grain of truth: a stateless widget CAN be rebuilt by its parent with new config, but it cannot change ITSELF: self-updating screens are stateful by definition.
Think first
Classify the booking screen
Next lessons build this screen: an event poster, the event title, a name TextField, a Book button, all vertically arranged with breathing space, over a Scaffold. Run all 3 axes over each piece before tapping.
Show the answer
Poster (Image) and title (Text): visible, stateless, childless leaves. TextField: visible, and the screen holding it is STATEFUL (typed text is changing data). Button: visible; its onPressed will call setState: the screen around it is stateful. Column: invisible, multi-child, arranging all of them. Padding: invisible, single-child, the breathing space. Scaffold: invisible skeleton framing the screen. The habit this builds: classify BEFORE you code, and the widget tree writes itself: which is literally next lesson's agenda.
Watch out
Classification traps
Mutating without setState: seats-- alone changes the variable and repaints NOTHING: the classic silent bug; every visible change goes through the gate.
child vs children: Center(children: [...]) does not compile; Row(child: ...) neither. Single-child widgets take child:, multi-child take children: [ ]: reading the error message solves it, reading the axis prevents it.
"Invisible" is not "unimportant": layout widgets are most of every real tree; invisible means no pixels of their own, not no effect.
Theory
Three questions before every widget
Internalise the interview: does it show? (visible or layout) : does it change? (stateless or stateful) : one child or many? Ask them for every widget you ever add, and Flutter's enormous catalogue collapses into a filing system. Unit 4 now walks the catalogue's first shelf: the visible four (Text, Image, Button, Icon), each through its constructor and named-parameter properties.
Summary
Key takeaways
- Everything on screen is a widget; the UI is a tree of them, configured via named parameters.
- Axis 1: visible widgets show pixels or take input; invisible ones (Row, Column, Center, Padding, Stack, Scaffold) arrange others.
- Axis 2: StatelessWidget renders fixed config; StatefulWidget owns a State object, and setState(() {...}) mutates + rebuilds.
- Changing data without setState updates nothing on screen: the classic bug.
- Axis 3: single-child widgets take child:; multi-child take children: [ ].
- Decide the kind by asking: show? change? how many children?
- Memory hook: show, change, children: the 3-question widget interview.