Flutter Widget Basics

Widget is the basic building block of Flutter UI.

In Flutter, everything is a Widget, from simple text to complex page layouts are all composed of Widgets.


What is a Widget?

Widget is a Dart class that describes the appearance and behavior of UI. Every Flutter app is essentially a tree structure composed of Widgets, called the Widget tree.

Example: The simplest Widget example

import 'package:flutter/material.dart';

// Define a simple Widget
class HelloWidget extends StatelessWidget {
  const HelloWidget({super.key});

  @override
  Widget build(BuildContext context) {
    // Return a Text Widget that displays "Hello World"
    return const Text('Hello World');
  }
}

StatelessWidget - stateless component

StatelessWidget is an immutable Widget. Once created, its properties cannot be changed. It is suitable for scenarios that display static content, such as text, images, icons, etc.

Basic Structure

Example: StatelessWidget Example

import 'package:flutter/material.dart';

// Define a stateless widget
class MyTextWidget extends StatelessWidget {
  // Constructor parameters (immutable properties)
  final String text;
  final Color textColor;
  final double fontSize;

  // Use const constructor
  const MyTextWidget({
    super.key,
    required this.text,
    this.textColor = Colors.black,
    this.fontSize = 16.0,
  });

  @override
  Widget build(BuildContext context) {
    // build method returns another Widget
    return Text(
      text,
      style: TextStyle(
        color: textColor,
        fontSize: fontSize,
      ),
    );
  }
}

// Usage example
// MyTextWidget(text: 'Hello', textColor: Colors.red)

Applicable scenarios

  • Static text display
  • Image display
  • Icon display
  • Layout that does not change over time

StatefulWidget - stateful component

StatefulWidget is a mutable Widget that can update the UI as internal data changes. It is suitable for scenarios that need to respond to user interactions or data changes.

Basic Structure

Example: StatefulWidget example

import 'package:flutter/material.dart';

// Define a stateful widget
class CounterWidget extends StatefulWidget {
  const CounterWidget({super.key});

  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

// State class holds mutable state
class _CounterWidgetState extends State<CounterWidget> {
  // Counter state
  int _count = 0;

  // Method to increment the counter
  void _increment() {
    // Call setState to notify the framework that the state has changed
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        // Display current count
        Text(
          'Counter: $_count',
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(height: 16),
        // Increment button
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Increase'),
        ),
      ],
    );
  }
}

setState method

In StatefulWidget, if the state changes, you must callsetStatethe method to notify Flutter to rebuild the UI.

If the state is modified but setState is not called, the UI will not update. This is because Flutter uses setState to determine whether the Widget needs to be rebuilt.

Applicable scenarios

  • Dynamic data such as counters, timers, etc.
  • Form input
  • Adding, deleting, and modifying list items
  • User interaction response

build method

Every Widget must implementbuildthe method, which returns a part of the Widget tree.

Basic rules

RulesDescription
Return ValueIt must return a Widget, and cannot return null.
ParameterReceives a BuildContext parameter, representing the position in the Widget tree.
Call timingFirst build, parent Widget rebuild, and state changes

Example: build method example

@override
Widget build(BuildContext context) {
  // BuildContext provides access to themes, theme information, etc.
  // For example, get the current theme color
  final theme = Theme.of(context);

  // Return a Widget
  return Container(
    padding: const EdgeInsets.all(16.0),
    decoration: BoxDecoration(
      color: theme.colorScheme.primaryContainer,
      borderRadius: BorderRadius.circular(8),
    ),
    child: Text(
      'Hello Flutter',
      style: TextStyle(
        color: theme.colorScheme.onPrimaryContainer,
        fontSize: 20,
      ),
    ),
  );
}

Commonly used basic Widgets

Text - text display

Example: Text Widget

// Basic text
const Text('Hello World')

// Text with style
Text(
  'Hello Flutter',
  style: TextStyle(
    fontSize: 20,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
  ),
)

// Text with optional style
Text.rich(
  TextSpan(
    text: 'Hello ',
    children: [
      TextSpan(
        text: 'Flutter',
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ],
  ),
)

Icon

Example: Icon Widget

// Use Material Icons
const Icon(Icons.home)              // Home icon
const Icon(Icons.star, color: Colors.yellow)  // Colored star
const Icon(Icons.settings, size: 48)  // Settings icon of size 48

Image

Example: Image Widget

// Load image from network
Image.network('https://example.com/image.png')

// Load image from local assets
Image.asset('assets/images/logo.png')

// Load image from file
Image.file(File('path/to/image.png'))

// Image with parameters
Image.network(
  'https://example.com/image.png',
  width: 200,
  height: 200,
  fit: BoxFit.cover,
)

Button

Example: Button Widget

// Text button
TextButton(
  onPressed: () { /* Handle click */ },
  child: const Text('Text button'),
)

// Floating action button
FloatingActionButton(
  onPressed: () { /* Handle click */ },
  child: const Icon(Icons.add),
)

// ElevatedButton - button with shadow
ElevatedButton(
  onPressed: () { /* Handle click */ },
  child: const Text('Submit'),
)

// Button with icon
ElevatedButton.icon(
  onPressed: () { /* Handle click */ },
  icon: const Icon(Icons.save),
  label: const Text('Save'),
)

Widget Combination

Flutter's power lies in its ability to combine Widgets. Through nesting, a simple Widget can build a complex UI.

Example: Composite Widget

class MyCard extends StatelessWidget {
  const MyCard({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      // Card is a Material Design card component
      elevation: 4,  // Shadow depth
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Title
            const Text(
              'Card title',
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            // Description text
            const Text(
              'This is the description of the card, which can contain multiple lines of text.',
            ),
            const SizedBox(height: 16),
            // Button row
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                TextButton(
                  onPressed: () {},
                  child: const Text('Cancel'),
                ),
                const SizedBox(width: 8),
                ElevatedButton(
                  onPressed: () {},
                  child: const Text('Confirm'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
other extensions