Widgets And Rendering
Flutter UI is widget composition. A widget is an immutable description of part of the UI for the current configuration and state.
Minimal Shape
import 'package:flutter/material.dart';
void main() => runApp(const App());
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(child: Text('Hello Flutter')),
),
);
}
}
Use StatelessWidget when the widget only depends on constructor inputs and inherited context. Use StatefulWidget when the widget owns local mutable UI state.
Widget Rules
| Topic | Practical rule |
|---|---|
build() | Keep it fast and side-effect free |
const widgets | Use them when constructor inputs are compile-time constants |
| Keys | Add keys when preserving identity across reorder, insert, or remove operations matters |
| Layout | Constraints flow down, sizes flow up, parent sets position |
| Material | Use for Material Design apps and Android-friendly defaults |
| Cupertino | Use for iOS-styled controls where platform feel matters |
Local State Example
class CounterButton extends StatefulWidget {
const CounterButton({super.key});
@override
State<CounterButton> createState() => _CounterButtonState();
}
class _CounterButtonState extends State<CounterButton> {
int count = 0;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => count += 1),
child: Text('Count: $count'),
);
}
}
This is correct for local button state. It is wrong for shared account state, cart state, sync state, or persisted settings.
Gotcha: Rebuilds are normal. The bug is expensive work during rebuild, unstable identity, or state stored in the wrong scope.