Перейти к основному содержимому

Flutter Widgets 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​