Skip to main content

Flutter Widgets Complete Guide

A comprehensive guide to Flutter widgets with detailed explanations, use cases, and practical examples. This guide helps you understand when, why, and how to use each widget effectively.

Table of Contents

Widget Fundamentals

Understanding Widgets

What are Widgets? Widgets are the building blocks of Flutter UI. Everything you see on screen is a widget - from text and buttons to complex layouts. Widgets describe what their view should look like given their current configuration and state.

Key Concepts:

  • Immutable: Widgets are immutable - once created, they cannot be changed
  • Composition: Complex UIs are built by composing simple widgets
  • Rebuild: When state changes, widgets rebuild to reflect new state

Widget Types

StatelessWidget

When to use: When your widget doesn't need to maintain any state or change over time.

Use cases:

  • Display static content (text, images, icons)
  • Show data that doesn't change
  • Simple UI components that don't respond to user input
// Stateless Widget - immutable, no internal state
class WelcomeMessage extends StatelessWidget {
final String userName;

const WelcomeMessage({Key? key, required this.userName}) : super(key: key);


Widget build(BuildContext context) {
return Text('Welcome, $userName!');
}
}

// Usage
WelcomeMessage(userName: 'John')

StatefulWidget

When to use: When your widget needs to maintain state that can change over time.

Use cases:

  • Forms with user input
  • Animations
  • Widgets that respond to user interactions
  • Data that changes based on external factors
// Stateful Widget - can change over time
class CounterWidget extends StatefulWidget {

_CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;

void _increment() {
setState(() {
_count++;
});
}


Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: Text('Increment'),
),
],
);
}
}

Widget Tree Structure

Understanding the Widget Tree: Flutter builds your UI as a tree of widgets. Each widget can have children, creating a hierarchical structure.

MaterialApp(                    // Root widget
home: Scaffold( // Provides basic app structure
appBar: AppBar( // Top app bar
title: Text('My App'),
),
body: Column( // Main content area
children: [
Text('Hello'), // Child widget
Container( // Another child widget
child: Text('World'),
),
],
),
),
)

Why this matters:

  • Performance: Flutter only rebuilds widgets that actually changed
  • Layout: Parent widgets control how children are positioned and sized
  • Inheritance: Child widgets can access data from parent widgets through context

Layout Widgets

Basic Layout Widgets

Column

What it does: Arranges its children in a vertical array.

When to use:

  • Stacking widgets vertically (top to bottom)
  • Creating forms with multiple input fields
  • Building page layouts with header, content, and footer

Key properties:

  • mainAxisAlignment: Controls vertical alignment
  • crossAxisAlignment: Controls horizontal alignment
  • mainAxisSize: Controls how much vertical space to take
// Basic Column
Column(
children: [
Text('Header'),
Text('Content'),
Text('Footer'),
],
)

// Column with alignment
Column(
mainAxisAlignment: MainAxisAlignment.center, // Center vertically
crossAxisAlignment: CrossAxisAlignment.start, // Align left horizontally
children: [
Text('Item 1'),
Text('Item 2'),
Text('Item 3'),
],
)

// Column that takes full height
Column(
mainAxisSize: MainAxisSize.max, // Take all available height
children: [
Expanded(child: Text('Takes remaining space')),
Text('Fixed height'),
],
)

Row

What it does: Arranges its children in a horizontal array.

When to use:

  • Placing widgets side by side
  • Creating navigation bars
  • Building form layouts with labels and inputs

Key properties:

  • mainAxisAlignment: Controls horizontal alignment
  • crossAxisAlignment: Controls vertical alignment
  • mainAxisSize: Controls how much horizontal space to take
// Basic Row
Row(
children: [
Icon(Icons.star),
Text('Rating: 4.5'),
],
)

// Row with space distribution
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // Space between items
children: [
Text('Left'),
Text('Center'),
Text('Right'),
],
)

// Row with flexible children
Row(
children: [
Text('Label: '),
Expanded(
child: TextField(decoration: InputDecoration(hintText: 'Enter value')),
),
],
)

Stack

What it does: Overlays multiple widgets on top of each other.

When to use:

  • Creating overlays (like badges on icons)
  • Building complex layouts with background and foreground elements
  • Implementing floating action buttons
  • Creating image overlays with text

Key properties:

  • alignment: Controls how positioned children are aligned
  • fit: Controls how non-positioned children are sized
// Basic Stack
Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
top: 10,
left: 10,
child: Text('Overlay text'),
),
],
)

// Stack with centered overlay
Stack(
alignment: Alignment.center, // Center non-positioned children
children: [
Image.network('https://example.com/image.jpg'),
Container(
padding: EdgeInsets.all(8),
color: Colors.black54,
child: Text(
'Overlay',
style: TextStyle(color: Colors.white),
),
),
],
)

// Badge on icon
Stack(
children: [
Icon(Icons.notifications, size: 30),
Positioned(
right: 0,
top: 0,
child: Container(
padding: EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
constraints: BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
'3',
style: TextStyle(
color: Colors.white,
fontSize: 10,
),
textAlign: TextAlign.center,
),
),
),
],
)

Advanced Layout Widgets

Expanded

What it does: Forces a child of a Row, Column, or Flex to expand to fill the available space.

When to use:

  • Making a widget take up remaining space in a Row/Column
  • Creating flexible layouts where some elements are fixed size and others expand
  • Building responsive layouts

Key properties:

  • flex: Controls how much space to take relative to other Expanded widgets
// Basic Expanded
Row(
children: [
Text('Fixed width text'),
Expanded(
child: Text('This text will take all remaining horizontal space'),
),
],
)

// Multiple Expanded widgets
Row(
children: [
Expanded(
flex: 1, // Takes 1/3 of space
child: Container(color: Colors.red),
),
Expanded(
flex: 2, // Takes 2/3 of space
child: Container(color: Colors.blue),
),
],
)

// Form layout with label and input
Row(
children: [
Text('Email: '),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter your email',
border: OutlineInputBorder(),
),
),
),
],
)

Flexible

What it does: Similar to Expanded but allows the child to be smaller than the available space.

When to use:

  • When you want a widget to be flexible but not necessarily fill all space
  • Creating layouts where widgets can shrink if needed
  • Building responsive designs
// Flexible vs Expanded
Row(
children: [
Text('Fixed'),
Flexible(
child: Text('Can shrink if needed'),
),
Expanded(
child: Text('Must take remaining space'),
),
],
)

// Flexible with flex factor
Row(
children: [
Flexible(
flex: 1,
child: Container(
height: 50,
color: Colors.red,
child: Text('Can shrink'),
),
),
Flexible(
flex: 2,
child: Container(
height: 50,
color: Colors.blue,
child: Text('Takes more space when available'),
),
),
],
)

Wrap

What it does: Automatically wraps its children to the next line when they don't fit.

When to use:

  • Creating tag clouds or chip lists
  • Building responsive grids
  • Displaying dynamic content that might overflow

Key properties:

  • spacing: Horizontal space between children
  • runSpacing: Vertical space between lines
  • alignment: How children are aligned within each line
// Basic Wrap
Wrap(
children: [
Chip(label: Text('Flutter')),
Chip(label: Text('Dart')),
Chip(label: Text('Mobile Development')),
Chip(label: Text('Cross-platform')),
Chip(label: Text('UI Framework')),
],
)

// Wrap with spacing
Wrap(
spacing: 8.0, // Horizontal space between children
runSpacing: 4.0, // Vertical space between lines
alignment: WrapAlignment.center, // Center children in each line
children: [
ActionChip(
label: Text('Action 1'),
onPressed: () {},
),
ActionChip(
label: Text('Action 2'),
onPressed: () {},
),
ActionChip(
label: Text('Action 3'),
onPressed: () {},
),
],
)

Container vs SizedBox

Container vs SizedBox - Understanding the Difference:

SizedBox

What it does: A widget with a specified size that forces its child to be exactly that size.

When to use:

  • When you need a widget with exact dimensions
  • Creating spacing between widgets
  • When you don't need decoration or padding
  • Performance-critical scenarios (lighter than Container)
// SizedBox with child
SizedBox(
width: 100,
height: 100,
child: Text('Fixed size text'),
)

// SizedBox for spacing
Column(
children: [
Text('First item'),
SizedBox(height: 20), // 20px vertical spacing
Text('Second item'),
],
)

// SizedBox as spacer
Row(
children: [
Text('Left'),
SizedBox(width: 50), // 50px horizontal spacing
Text('Right'),
],
)

Container

What it does: A convenience widget that combines common painting, positioning, and sizing widgets.

When to use:

  • When you need decoration (colors, borders, shadows)
  • When you need padding or margin
  • When you need complex styling
  • When you need to constrain a child's size with additional styling
// Container with decoration
Container(
width: 100,
height: 100,
margin: EdgeInsets.all(8.0), // Space outside the container
padding: EdgeInsets.all(16.0), // Space inside the container
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8.0),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 4.0,
offset: Offset(0, 2),
),
],
),
child: Text('Styled container'),
)

// Container with just padding
Container(
padding: EdgeInsets.all(16.0),
child: Text('Padded text'),
)

// Container with constraints
Container(
constraints: BoxConstraints(
minWidth: 100,
maxWidth: 200,
minHeight: 50,
maxHeight: 100,
),
child: Text('Constrained text'),
)

Key Differences:

  • SizedBox: Lightweight, exact sizing, no decoration
  • Container: Feature-rich, can have decoration, padding, margin, constraints

Performance Tip: Use SizedBox when you only need sizing, use Container when you need styling.

Padding & Margin

Padding

What it does: Adds space inside a widget (between the widget's border and its content).

When to use:

  • Adding space around text or content
  • Creating breathing room within widgets
  • Consistent spacing in layouts
// Basic padding
Padding(
padding: EdgeInsets.all(16.0),
child: Text('Text with padding'),
)

// Different padding for each side
Padding(
padding: EdgeInsets.only(
left: 16.0,
right: 16.0,
top: 8.0,
bottom: 8.0,
),
child: Text('Custom padding'),
)

// Symmetric padding
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, // Left and right
vertical: 8.0, // Top and bottom
),
child: Text('Symmetric padding'),
)

Margin (via Container)

What it does: Adds space outside a widget (between the widget and its neighbors).

When to use:

  • Creating space between widgets
  • Building layouts with gaps
  • Separating sections of your UI
// Container with margin
Container(
margin: EdgeInsets.all(8.0),
child: Text('Text with margin'),
)

// Margin between widgets
Column(
children: [
Container(
margin: EdgeInsets.only(bottom: 16.0),
child: Text('First widget'),
),
Text('Second widget'),
],
)

Text & Typography

Text Widgets

Text

What it does: Displays a string of text with single styling.

When to use:

  • Displaying simple text content
  • Labels and titles
  • When all text has the same style
// Basic text
Text('Hello World')

// Text with style
Text(
'Styled Text',
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
color: Colors.blue,
fontFamily: 'Roboto',
letterSpacing: 1.2,
height: 1.5, // Line height multiplier
),
)

// Text with alignment
Text(
'Centered text',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
)

// Text with overflow handling
Text(
'This is a very long text that might overflow the available space',
overflow: TextOverflow.ellipsis, // Shows "..." when text overflows
maxLines: 2, // Limit to 2 lines
)

RichText

What it does: Displays text with multiple styles within the same text widget.

When to use:

  • When you need different styles within the same text
  • Highlighting specific words or phrases
  • Creating complex text layouts
  • Links within text
// RichText with multiple styles
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black, fontSize: 16), // Default style
children: [
TextSpan(text: 'Hello '),
TextSpan(
text: 'World',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
fontSize: 20,
),
),
TextSpan(text: '!'),
],
),
)

// RichText with clickable spans
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
children: [
TextSpan(text: 'Click '),
TextSpan(
text: 'here',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => print('Link tapped'),
),
TextSpan(text: ' to continue'),
],
),
)

Text Input Widgets

TextField

What it does: Creates a material design text input field.

When to use:

  • Single-line text input
  • Search fields
  • Username/password fields
  • Any form input that doesn't need validation
// Basic TextField
TextField(
decoration: InputDecoration(
labelText: 'Enter your name',
hintText: 'John Doe',
border: OutlineInputBorder(),
),
onChanged: (value) {
print('Text changed: $value');
},
)

// TextField with prefix icon
TextField(
decoration: InputDecoration(
labelText: 'Email',
hintText: 'example@email.com',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
)

// TextField with suffix and validation
TextField(
decoration: InputDecoration(
labelText: 'Password',
suffixIcon: Icon(Icons.visibility),
border: OutlineInputBorder(),
errorText: _passwordError, // Show error if not null
),
obscureText: true, // Hide text (for passwords)
onChanged: (value) {
setState(() {
_passwordError = value.length < 6 ? 'Password too short' : null;
});
},
)

TextFormField

What it does: A TextField that integrates with Form validation.

When to use:

  • Forms with validation
  • When you need to validate input before submission
  • Complex forms with multiple fields
// TextFormField with validation
TextFormField(
decoration: InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter an email';
}
if (!value.contains('@')) {
return 'Please enter a valid email';
}
return null;
},
onSaved: (value) {
_email = value;
},
)

// Using with Form widget
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
validator: (value) => value?.isEmpty ?? true ? 'Required' : null,
),
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (value) => value?.isEmpty ?? true ? 'Required' : null,
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// Process form data
}
},
child: Text('Submit'),
),
],
),
)

Interactive Widgets

Button Widgets

ElevatedButton

What it does: A material design button that lifts when pressed.

When to use:

  • Primary actions in your app
  • Call-to-action buttons
  • When you want the button to stand out
// Basic ElevatedButton
ElevatedButton(
onPressed: () {
print('Button pressed');
},
child: Text('Press Me'),
)

// ElevatedButton with icon
ElevatedButton.icon(
onPressed: () {},
icon: Icon(Icons.save),
label: Text('Save'),
)

// ElevatedButton with custom style
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
primary: Colors.blue,
onPrimary: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text('Custom Button'),
)

// Disabled button
ElevatedButton(
onPressed: _isLoading ? null : () {}, // null disables the button
child: _isLoading
? CircularProgressIndicator(color: Colors.white)
: Text('Submit'),
)

TextButton

What it does: A flat button with no elevation.

When to use:

  • Secondary actions
  • Navigation buttons
  • When you want a subtle button
  • In dialogs and bottom sheets
// Basic TextButton
TextButton(
onPressed: () {},
child: Text('Cancel'),
)

// TextButton with custom style
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
primary: Colors.red,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
child: Text('Delete'),
)

IconButton

What it does: A button that displays an icon.

When to use:

  • Toolbar actions
  • Floating action buttons
  • Compact actions
  • When space is limited
// Basic IconButton
IconButton(
onPressed: () {},
icon: Icon(Icons.favorite),
)

// IconButton with tooltip
IconButton(
onPressed: () {},
icon: Icon(Icons.help),
tooltip: 'Help',
)

// IconButton with custom size
IconButton(
onPressed: () {},
icon: Icon(Icons.menu),
iconSize: 30,
color: Colors.blue,
)

Gesture Detection

GestureDetector

What it does: Detects gestures on its child widget.

When to use:

  • Making any widget tappable
  • Custom gesture handling
  • When you need fine-grained control over gestures
// Basic tap detection
GestureDetector(
onTap: () => print('Tapped'),
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(16),
child: Text('Tap me', style: TextStyle(color: Colors.white)),
),
)

// Multiple gestures
GestureDetector(
onTap: () => print('Single tap'),
onDoubleTap: () => print('Double tap'),
onLongPress: () => print('Long press'),
onPanUpdate: (details) => print('Pan: ${details.delta}'),
child: Container(
color: Colors.green,
child: Text('Multi-gesture widget'),
),
)

// Drag detection
GestureDetector(
onPanUpdate: (details) {
setState(() {
_position += details.delta;
});
},
child: Container(
width: 100,
height: 100,
color: Colors.red,
transform: Matrix4.translationValues(_position.dx, _position.dy, 0),
),
)

InkWell

What it does: A rectangular area that responds to touch with a ripple effect.

When to use:

  • Making widgets tappable with material design ripple
  • List items that should be tappable
  • When you want the material design touch feedback
// Basic InkWell
InkWell(
onTap: () => print('Tapped with ripple'),
child: Container(
padding: EdgeInsets.all(16),
child: Text('Tap with ripple effect'),
),
)

// InkWell with custom splash color
InkWell(
onTap: () {},
splashColor: Colors.blue.withOpacity(0.3),
highlightColor: Colors.blue.withOpacity(0.1),
child: Container(
padding: EdgeInsets.all(16),
child: Text('Custom ripple colors'),
),
)

// InkWell in a list
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () => _onItemTap(index),
child: ListTile(
title: Text(items[index].title),
subtitle: Text(items[index].subtitle),
),
);
},
)

Lists & Grids

ListView Widgets

ListView

What it does: A scrollable list of widgets arranged linearly.

When to use:

  • Displaying a list of items
  • When you have a small, fixed number of items
  • Simple lists that don't need optimization
// Basic ListView
ListView(
children: [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
)

// ListView with custom items
ListView(
padding: EdgeInsets.all(16),
children: [
Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text('John Doe'),
subtitle: Text('Software Developer'),
trailing: Icon(Icons.arrow_forward),
onTap: () => print('Tapped John'),
),
),
Card(
child: ListTile(
leading: Icon(Icons.person),
title: Text('Jane Smith'),
subtitle: Text('Designer'),
trailing: Icon(Icons.arrow_forward),
onTap: () => print('Tapped Jane'),
),
),
],
)

ListView.builder

What it does: Creates a ListView with items built on demand.

When to use:

  • Large lists (performance optimization)
  • Dynamic lists where items are loaded as needed
  • When you have a large number of items
// ListView.builder for large lists
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
onTap: () => _onItemTap(index),
);
},
)

// ListView.builder with different item types
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];

if (item.type == 'header') {
return Container(
padding: EdgeInsets.all(16),
color: Colors.grey[200],
child: Text(
item.title,
style: TextStyle(fontWeight: FontWeight.bold),
),
);
} else {
return ListTile(
title: Text(item.title),
subtitle: Text(item.subtitle),
);
}
},
)

ListView.separated

What it does: Creates a ListView with separators between items.

When to use:

  • When you want visual separation between items
  • Lists that need dividers or custom separators
  • When you want consistent spacing
// ListView.separated with dividers
ListView.separated(
itemCount: items.length,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (context, index) {
return ListTile(title: Text(items[index]));
},
)

// ListView.separated with custom separators
ListView.separated(
itemCount: items.length,
separatorBuilder: (context, index) => SizedBox(height: 8),
itemBuilder: (context, index) {
return Card(
child: ListTile(title: Text(items[index])),
);
},
)

GridView Widgets

GridView.count

What it does: Creates a grid with a fixed number of tiles in the cross axis.

When to use:

  • When you know the number of columns you want
  • Simple grids with fixed layout
  • When you have a small number of items
// Basic GridView.count
GridView.count(
crossAxisCount: 2, // 2 columns
children: [
Container(color: Colors.red, child: Center(child: Text('1'))),
Container(color: Colors.blue, child: Center(child: Text('2'))),
Container(color: Colors.green, child: Center(child: Text('3'))),
Container(color: Colors.yellow, child: Center(child: Text('4'))),
],
)

// GridView.count with spacing
GridView.count(
crossAxisCount: 3,
crossAxisSpacing: 8.0, // Horizontal space between items
mainAxisSpacing: 8.0, // Vertical space between items
children: List.generate(9, (index) {
return Card(
child: Center(child: Text('Item ${index + 1}')),
);
}),
)

GridView.builder

What it does: Creates a grid with items built on demand.

When to use:

  • Large grids (performance optimization)
  • Dynamic grids where items are loaded as needed
  • When you have a large number of items
// GridView.builder for large grids
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
),
itemCount: items.length,
itemBuilder: (context, index) {
return Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.star, size: 32),
SizedBox(height: 8),
Text(items[index].title),
],
),
);
},
)

// GridView.builder with different item sizes
GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 150, // Maximum width per item
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
),
itemCount: items.length,
itemBuilder: (context, index) {
return Card(
child: Center(child: Text(items[index])),
);
},
)

Material Design Widgets

Card

What it does: A material design card with elevation and rounded corners.

When to use:

  • Displaying content in a contained area
  • List items that need visual separation
  • Information cards with multiple elements
// Basic Card
Card(
child: ListTile(
title: Text('Card Title'),
subtitle: Text('Card subtitle'),
),
)

// Card with custom content
Card(
elevation: 4,
margin: EdgeInsets.all(8),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Article Title',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('Article description goes here...'),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Author: John Doe'),
Text('2024-01-15'),
],
),
],
),
),
)

AppBar

What it does: A material design app bar that displays at the top of the screen.

When to use:

  • Main navigation bar for your app
  • Displaying page titles and actions
  • Consistent app branding
// Basic AppBar
AppBar(
title: Text('My App'),
)

// AppBar with actions
AppBar(
title: Text('My App'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {},
),
],
)

// AppBar with leading widget
AppBar(
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
title: Text('My App'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
)

FloatingActionButton

What it does: A circular floating button that hovers over the content.

When to use:

  • Primary action for the current screen
  • Quick access to common actions
  • When you want the action to be prominent
// Basic FloatingActionButton
FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
)

// FloatingActionButton with label
FloatingActionButton.extended(
onPressed: () {},
icon: Icon(Icons.add),
label: Text('Add Item'),
)

// FloatingActionButton with custom style
FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Icon(Icons.delete),
)

Performance Considerations

When to Use Different List Widgets

ListView vs ListView.builder:

  • Use ListView for small, fixed lists (< 50 items)
  • Use ListView.builder for large or dynamic lists

GridView.count vs GridView.builder:

  • Use GridView.count for small, fixed grids
  • Use GridView.builder for large or dynamic grids

Widget Optimization Tips

  1. Use const constructors when possible:
// Good - const constructor
const Text('Hello')

// Avoid - non-const constructor
Text('Hello')
  1. Extract widgets for complex UI:
// Good - extracted widget
class UserCard extends StatelessWidget {
final User user;

const UserCard({Key? key, required this.user}) : super(key: key);


Widget build(BuildContext context) {
return Card(
child: ListTile(
title: Text(user.name),
subtitle: Text(user.email),
),
);
}
}
  1. Use appropriate list widgets for performance:
// For large lists, use builder pattern
ListView.builder(
itemCount: largeList.length,
itemBuilder: (context, index) => UserCard(user: largeList[index]),
)

References