Skip to main content

Working with Stateless Widgets

1. Creating StatelessWidget Class

A StatelessWidget is a widget that does not change during its lifetime. It is used for UI elements that do not require state management.

Property Description Example
key Optional key to identify the widget in the widget tree. key: const Key('myWidget')
build Required method that returns the widget tree. @override Widget build(BuildContext context) { return Text('Hello'); }

Example: Basic StatelessWidget

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text('Hello, Flutter!');
  }
}

2. Implementing build() Method

Method Description Return Type
build(BuildContext context) Required method for all stateless widgets. Defines the UI of the widget. Widget

Example: Basic Stateless Widget

<Widget> MyWidget() {
  return Container(
    child: Text('Hello, Flutter!'),
  );
}
Note: The build method is called every time the widget needs to be rebuilt, and it must return a Widget.

3. Using Constructor Parameters

Parameter Type Description Usage Example
required Ensures a parameter is provided when creating the widget const MyWidget({required String title});
optional Allows a parameter to have a default value const MyWidget({String title = 'Default'});
named Parameters specified with curly braces {} const MyWidget({required String title, int? count});
positional Parameters specified with square brackets [] const MyWidget([String title = 'Default']);

Example: Using Constructor Parameters in a Widget

class GreetingWidget extends StatelessWidget {
  final String name;
  final int age;

  const GreetingWidget({
    Key? key,
    required this.name,
    this.age = 0,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text('Hello, $name! You are $age years old.');
  }
}

4. Understanding Widget Lifecycle

Phase Description Methods Notes
Construction Widget is created MyWidget({Key? key}) : super(key: key); Only constructor logic here
Mounting Widget is inserted into the tree void initState() { ... } Called once after the widget is mounted
Building Widget is built and rendered Widget build(BuildContext context) { ... } Core rendering logic
Updating Widget is updated due to changes in state or props bool updateShouldNotify() { ... } Used in ChangeNotifier or InheritedWidget
Unmounting Widget is removed from the tree void dispose() { ... } Clean up resources like streams or timers

Example: Basic Widget Lifecycle

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  int counter = 0;

  @override
  void initState() {
    super.initState();
    print('Widget initialized');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Lifecycle Example')),
      body: Center(
        child: Text('Counter: $counter'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            counter++;
          });
        },
        child: Icon(Icons.add),
      ),
    );
  }

  @override
  void dispose() {
    print('Widget disposed');
    super.dispose();
  }
}
Note: The build method can be called multiple times during the widget's lifecycle, but initState and dispose are called only once.

Key Lifecycle Events

  • initState: Initialize state variables and subscriptions
  • build: Return the widget tree to render
  • dispose: Clean up resources like streams or timers

5. Creating Custom Stateless Widgets

Custom stateless widgets in Flutter are created by extending the StatelessWidget class and implementing the build method. These widgets are immutable and do not maintain any state during their lifecycle.

Property Description Example
build Required method that returns a Widget tree. This is where the UI is defined.
Widget build(BuildContext context) {
  return Text('Hello, World!');
}

Example: Simple Custom Stateless Widget

class GreetingWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Welcome to Flutter!');
  }
}

Example: Custom Stateless Widget with Parameters

class ProfileCard extends StatelessWidget {
  final String name;
  final String title;

  ProfileCard({required this.name, required this.title});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(name, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
            Text(title, style: TextStyle(fontSize: 16, color: Colors.grey)),
          ],
        ),
      ),
    );
  }
}

6. Using const Constructors

When building Flutter widgets, using const constructors can significantly improve performance by enabling compile-time optimizations and reducing memory usage.

Constructor Description Usage Example
const Text() Creates a text widget with compile-time constants. const Text("Hello World", style: TextStyle(fontSize: 16))
const Container() Creates a container widget with immutable properties.
const Container(
  width: 100,
  height: 50,
  color: Colors.blue,
)
const SizedBox() Creates a fixed-size widget with no children. const SizedBox(width: 20, height: 20)
Note: All arguments to const widgets must be compile-time constants. This includes strings, numbers, booleans, and null values.
Warning: Using const with mutable values or runtime expressions will cause a compile-time error.

Benefits of const Constructors

  • Performance: Reduces widget rebuilds and memory allocation.
  • Memory Efficiency: Widgets are created once at compile time.
  • Reusability: Same widget instance reused across builds.

7. Passing Callbacks as Parameters

Parameter Type Description
onPressed VoidCallback? Callback function executed when the button is pressed
onChanged ValueChanged<T>? Callback function executed when a value changes (e.g., in TextField)
onTap GesturesTapCallback? Callback function executed when the widget is tapped

Example: Button with onPressed callback

TextButton(
  onPressed: () {
    print('Button pressed!');
  },
  child: Text('Press Me'),
)

Example: TextField with onChanged callback

TextField(
  onChanged: (String value) {
    print('Text changed to: $value');
  },
  decoration: InputDecoration(
    hintText: 'Enter text',
  ),
)

8. Implementing Widget Composition

Example: Basic Widget Composition

import &#x27;package:flutter/material.dart&#x27;;

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Composition Example")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("Hello"),
            Text("World"),
          ],
        ),
      ),
    );
  }
}
Property Description Usage
child The widget that is composed into the parent widget. Used in widgets like Container, Center, Row.
children A list of widgets that are composed into the parent widget. Used in Column, Row, ListView.
Note: Widget composition in Flutter is achieved through the child and children properties of widgets.

Comparison: Widget Composition vs Inheritance

  • Composition: Widgets are built by combining smaller widgets.
  • Inheritance: Widgets inherit properties from a parent class (not used in Flutter).

9. Using Key Parameters

Parameter Description Usage
key Uniquely identifies a widget in the widget tree const Key('myKey')
GlobalKey Used to identify widgets globally across the app GlobalKey<StatefulWidget> key = GlobalKey();
LocalKey Used to identify widgets within a local scope LocalKey key = ValueKey('value');

Example: Using Key in a List

class MyList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          title: Text('Item 1'),
          key: Key('item_1'),
        ),
        ListTile(
          title: Text('Item 2'),
          key: Key('item_2'),
        ),
      ],
    );
  }
}
Note: Keys are essential for efficient widget rebuilding and state management in Flutter.

10. Creating Reusable UI Components

Reusable UI components in Flutter are created using custom widgets that encapsulate specific UI logic and layout. These components can be composed of multiple widgets and can accept parameters to customize their behavior.

Component Description Usage
Custom Widget A widget that extends StatelessWidget or StatefulWidget to encapsulate reusable UI logic. Define a new class extending StatelessWidget or StatefulWidget with a build method.
Widget Parameters Properties passed to a custom widget to configure its appearance or behavior. Use constructor parameters in the widget class to accept configuration values.

Example: Custom Button Widget

class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;

  const CustomButton({Key? key, required this.text, required this.onPressed}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
    );
  }
}

Example: Reusable Card Component

class CustomCard extends StatelessWidget {
  final String title;
  final String content;

  const CustomCard({Key? key, required this.title, required this.content}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            SizedBox(height: 8),
            Text(content),
          ],
        ),
      ),
    );
  }
}

Was this article helpful?