Welcome to the fascinating world of Flutter! As you embark on your journey to build beautiful and performant apps, you'll quickly discover that everything in Flutter is a widget. Think of widgets as the fundamental building blocks of your app's user interface. From simple text labels to complex navigation structures, each visual element and even layout concepts are represented by widgets.
Flutter's widget system is declarative. This means you describe what your UI should look like at any given point in time, and Flutter takes care of updating the UI efficiently when the underlying state changes. This is a powerful paradigm that leads to more predictable and maintainable code.
There are two main categories of widgets in Flutter: StatelessWidget and StatefulWidget. Understanding the difference is crucial for building dynamic and interactive applications.
StatelessWidget: A StatelessWidget is a widget that describes part of the user interface which does not depend on anything other than the configuration information passed into it. Its state cannot change over time. Think of it as a blueprint that renders the same UI every time it's built with the same configuration. Examples include a simple text label, an icon, or a fixed image.
class MyTextWidget extends StatelessWidget {
final String text;
const MyTextWidget({Key? key, required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(text);
}
}StatefulWidget: A StatefulWidget is a widget that describes a part of the user interface which can change dynamically over time. It has mutable state that can be changed by the user or by the app. When the state changes, the widget rebuilds itself to reflect the new state. Examples include a checkbox, a slider, or a text field where the user can input data.
class CounterWidget extends StatefulWidget {
const CounterWidget({Key? key}) : super(key: key);
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
ElevatedButton(onPressed: _incrementCounter, child: Text('Increment'))
],
);
}
}The setState() method is crucial for StatefullWidgets. When you call setState(), you're telling Flutter that the internal state of this widget has changed and that it needs to be rebuilt.
graph TD;
StatelessWidget["StatelessWidget (immutable state)"] --> build1[build()];
StatefulWidget["StatefulWidget (mutable state)"] --> createState[createState()];
createState --> State[_State Object];
State --> build2[build()];
build1 --> Widget;
build2 --> Widget;
State --> setState["setState() (triggers rebuild)"];
setState --> build2;
Flutter provides a rich catalog of pre-built widgets that cover a wide range of UI components and layout patterns. You can compose these widgets together to create complex and visually appealing interfaces. Common examples include Container, Row, Column, Text, Image, Icon, ListView, Scaffold, and many more.
As you progress, you'll also learn how to create your own custom widgets by combining existing ones or by extending StatelessWidget or StatefulWidget. This composability is a core strength of Flutter, allowing you to build reusable UI components and maintain a consistent design language across your app.