Stack and Positioned Widgets in Flutter
Stack and Positioned are important Flutter widgets for creating layered user interfaces. They allow multiple widgets to overlap each other and make it possible to place individual widgets at specific positions inside a parent area.
Stack is useful for interfaces such as image overlays, profile badges, floating buttons, banners, cards, notification indicators, gradients over images, custom headers, and layered dashboard components.
1. What Is the Stack Widget?
The Stack widget places its children relative to the edges of its available box and allows multiple children to overlap one another.
Unlike Row and Column, which normally arrange children next to each other, Stack places children on top of each other.
Stack
├── Background
├── Image
├── Overlay
├── Text
└── Button
2. Basic Stack Syntax
Stack(
children: [
Container(
width: 300,
height: 200,
color: Colors.blue,
),
const Text('Hello Flutter'),
],
)
In this example, the Text is painted above the Container because it appears later in the children list.
3. How Stack Works
A Stack contains two general types of children:
- Non-positioned children: Normal children that are not controlled by Positioned.
- Positioned children: Children wrapped with Positioned and given positioning values such as top, left, right, or bottom.
The Stack uses its non-positioned children when determining its size. Positioned children are then placed relative to the Stack according to their positioning properties.
4. Simple Stack Example
Stack(
children: [
Container(
width: 250,
height: 250,
color: Colors.red,
),
Container(
width: 200,
height: 200,
color: Colors.green,
),
Container(
width: 150,
height: 150,
color: Colors.blue,
),
],
)
The widgets overlap each other. The first child is painted first, and later children appear above earlier children.
5. Stack Layer Order
The order of children in a Stack determines their visual layering.
Stack(
children: [
BackgroundWidget(), // Bottom layer
ImageWidget(), // Middle layer
TextWidget(), // Top layer
],
)
The first child is at the bottom and subsequent children are painted above it.
6. What Is the Positioned Widget?
Positioned controls where a child is placed inside a Stack. It provides properties such as top, right, bottom, left, width, and height.
A Positioned widget must be a descendant of a Stack.
7. Basic Positioned Syntax
Stack(
children: [
Container(
width: 300,
height: 300,
color: Colors.grey,
),
Positioned(
top: 20,
left: 20,
child: Container(
width: 80,
height: 80,
color: Colors.blue,
),
),
],
)
The blue container is positioned 20 logical pixels from the top and 20 logical pixels from the left of the Stack.
8. Positioned Properties
| Property | Purpose |
| top | Distance from the top edge of the Stack. |
| right | Distance from the right edge of the Stack. |
| bottom | Distance from the bottom edge of the Stack. |
| left | Distance from the left edge of the Stack. |
| width | Specifies the child's width. |
| height | Specifies the child's height. |
| child | The widget being positioned. |
9. Positioned with top and left
Stack(
children: [
Container(
width: 300,
height: 200,
color: Colors.grey,
),
Positioned(
top: 20,
left: 30,
child: Container(
width: 100,
height: 60,
color: Colors.blue,
),
),
],
)
Here, the child starts 20 pixels from the top and 30 pixels from the left.
10. Positioned with top and right
Positioned(
top: 20,
right: 20,
child: Container(
width: 80,
height: 80,
color: Colors.red,
),
)
This places the widget near the top-right corner of the Stack.
11. Positioned with bottom and left
Positioned(
bottom: 20,
left: 20,
child: Container(
width: 80,
height: 80,
color: Colors.green,
),
)
This places the widget near the bottom-left corner.
12. Positioned with bottom and right
Positioned(
bottom: 20,
right: 20,
child: Container(
width: 80,
height: 80,
color: Colors.orange,
),
)
This places the widget near the bottom-right corner.
13. Centering a Widget in Stack
A widget can be centered using the Stack's alignment property.
Stack(
alignment: Alignment.center,
children: [
Container(
width: 300,
height: 200,
color: Colors.blue,
),
const Text(
'Centered Text',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
],
)
14. Using Positioned with Width and Height
You can specify the dimensions of a positioned child using width and height.
Stack(
children: [
Container(
width: 300,
height: 300,
color: Colors.grey,
),
Positioned(
top: 30,
left: 30,
width: 120,
height: 80,
child: Container(
color: Colors.blue,
),
),
],
)
15. Using Left and Right Together
When both left and right are provided, they can determine the horizontal size of the positioned child.
Stack(
children: [
Container(
width: 350,
height: 200,
color: Colors.grey,
),
Positioned(
left: 20,
right: 20,
bottom: 20,
height: 50,
child: Container(
color: Colors.black,
child: const Center(
child: Text(
'Bottom Content',
style: TextStyle(color: Colors.white),
),
),
),
),
],
)
16. Using Top and Bottom Together
When both top and bottom are provided, they can determine the vertical size of the child.
Stack(
children: [
Container(
width: 300,
height: 300,
color: Colors.grey,
),
Positioned(
top: 30,
bottom: 30,
left: 30,
width: 100,
child: Container(
color: Colors.blue,
),
),
],
)
17. Positioned.fill
Positioned.fill is a convenient constructor that positions a child so that its default left, top, right, and bottom values are zero.
This is especially useful when creating an overlay that should cover the entire Stack.
Stack(
children: [
Container(
width: 300,
height: 200,
color: Colors.blue,
),
Positioned.fill(
child: Container(
color: Colors.black54,
),
),
],
)
18. Image Overlay Using Stack
One of the most common uses of Stack is placing text over an image.
Stack(
children: [
Image.network(
'https://example.com/image.jpg',
width: double.infinity,
height: 250,
fit: BoxFit.cover,
),
const Positioned(
left: 20,
bottom: 20,
child: Text(
'Beautiful Landscape',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
],
)
19. Image with Gradient Overlay
A gradient overlay can improve text readability on images.
Stack(
children: [
Image.network(
'https://example.com/image.jpg',
width: double.infinity,
height: 300,
fit: BoxFit.cover,
),
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black87,
],
),
),
),
),
const Positioned(
left: 20,
bottom: 20,
child: Text(
'Flutter UI Design',
style: TextStyle(
color: Colors.white,
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
],
)
20. Profile Picture with Online Badge
Stack is useful for placing a status badge over a profile picture.
Stack(
children: [
const CircleAvatar(
radius: 45,
backgroundImage: NetworkImage(
'https://example.com/profile.jpg',
),
),
Positioned(
right: 0,
bottom: 0,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 3,
),
),
),
),
],
)
21. Notification Badge
A notification count can be placed over an icon using Stack and Positioned.
Stack(
clipBehavior: Clip.none,
children: [
const Icon(
Icons.notifications,
size: 35,
),
Positioned(
right: -5,
top: -5,
child: Container(
padding: const EdgeInsets.all(5),
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: const Text(
'5',
style: TextStyle(
color: Colors.white,
fontSize: 12,
),
),
),
),
],
)
22. Floating Action Button Style Overlay
Stack(
children: [
Container(
width: double.infinity,
height: 300,
color: Colors.blueGrey,
),
Positioned(
right: 20,
bottom: 20,
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
],
)
23. Product Card Using Stack
Card(
clipBehavior: Clip.antiAlias,
child: Stack(
children: [
Image.network(
'https://example.com/product.jpg',
width: double.infinity,
height: 250,
fit: BoxFit.cover,
),
Positioned(
top: 12,
right: 12,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'20% OFF',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
const Positioned(
left: 15,
bottom: 15,
child: Text(
'Smart Watch',
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),
],
),
)
24. Stack Alignment
The alignment property controls how non-positioned and partially positioned children are aligned.
Stack(
alignment: Alignment.center,
children: [
Container(
width: 250,
height: 250,
color: Colors.blue,
),
const Icon(
Icons.favorite,
color: Colors.white,
size: 60,
),
],
)
Common Alignment Values
Alignment.topLeft
Alignment.topCenter
Alignment.topRight
Alignment.centerLeft
Alignment.center
Alignment.centerRight
Alignment.bottomLeft
Alignment.bottomCenter
Alignment.bottomRight
25. StackFit
The fit property controls how non-positioned children are sized inside the Stack.
Stack(
fit: StackFit.expand,
children: [
Container(
color: Colors.blue,
),
const Center(
child: Text(
'Full Size Background',
style: TextStyle(color: Colors.white),
),
),
],
)
Common StackFit Values
| Value | Description |
| StackFit.loose | Children receive loose constraints. |
| StackFit.expand | Non-positioned children are forced to fill the Stack's available space. |
| StackFit.passthrough | Passes the constraints received by the Stack to its non-positioned children. |
26. Clip Behavior
The clipBehavior property controls whether content that extends outside the Stack's bounds is clipped.
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
right: -20,
top: -20,
child: const CircleAvatar(
radius: 30,
child: Icon(Icons.star),
),
),
],
)
Clip.none is useful when a badge or decorative element intentionally extends outside the Stack.
27. Stack with Container Background
Stack(
children: [
Container(
width: double.infinity,
height: 250,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20),
),
),
const Positioned(
left: 20,
top: 20,
child: Text(
'Welcome',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
),
const Positioned(
left: 20,
bottom: 20,
child: Text(
'Welcome to Flutter',
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
),
],
)
28. Stack Inside a SizedBox
A Stack often works best when its available size is clearly defined by its parent.
SizedBox(
width: 300,
height: 200,
child: Stack(
children: [
Container(
color: Colors.grey,
),
const Positioned(
top: 20,
left: 20,
child: Text('Top Left'),
),
const Positioned(
bottom: 20,
right: 20,
child: Text('Bottom Right'),
),
],
),
)
29. Stack Inside a Card
Card(
child: SizedBox(
height: 220,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.indigo,
),
),
const Positioned(
left: 20,
top: 20,
child: Icon(
Icons.flutter_dash,
color: Colors.white,
size: 50,
),
),
const Positioned(
left: 20,
bottom: 20,
child: Text(
'Flutter Course',
style: TextStyle(
color: Colors.white,
fontSize: 22,
),
),
),
],
),
),
)
30. Stack with Multiple Positioned Widgets
Stack(
children: [
Container(
width: 350,
height: 250,
color: Colors.grey,
),
Positioned(
top: 10,
left: 10,
child: Container(
width: 70,
height: 70,
color: Colors.red,
),
),
Positioned(
top: 10,
right: 10,
child: Container(
width: 70,
height: 70,
color: Colors.green,
),
),
Positioned(
bottom: 10,
left: 10,
child: Container(
width: 70,
height: 70,
color: Colors.blue,
),
),
Positioned(
bottom: 10,
right: 10,
child: Container(
width: 70,
height: 70,
color: Colors.orange,
),
),
],
)
31. Responsive Stack Layout
Stack can also be used in responsive layouts. Instead of relying on fixed dimensions everywhere, allow the parent to provide constraints and use widgets such as Positioned.fill and MediaQuery or LayoutBuilder when layout decisions are required.
LayoutBuilder(
builder: (context, constraints) {
final isSmall = constraints.maxWidth < 600;
return SizedBox(
height: isSmall ? 220 : 350,
width: double.infinity,
child: Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.blueGrey,
),
),
Positioned(
left: isSmall ? 16 : 40,
bottom: isSmall ? 16 : 30,
child: Text(
isSmall ? 'Mobile' : 'Large Screen',
style: const TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
],
),
);
},
)
32. Stack with Positioned.fill and Overlay
Stack(
children: [
Image.network(
'https://example.com/banner.jpg',
width: double.infinity,
height: 300,
fit: BoxFit.cover,
),
Positioned.fill(
child: Container(
color: Colors.black45,
),
),
const Center(
child: Text(
'Flutter Development',
style: TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
],
)
33. Stack with Button Overlay
Stack(
children: [
Container(
height: 250,
width: double.infinity,
color: Colors.blueGrey,
),
const Positioned(
left: 20,
top: 20,
child: Text(
'Featured Course',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
Positioned(
right: 20,
bottom: 20,
child: ElevatedButton(
onPressed: () {},
child: const Text('Learn More'),
),
),
],
)
34. Creating a Badge Widget
Widget buildBadge(String text) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20),
),
child: Text(
text,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
);
}
Stack(
children: [
Container(
width: 250,
height: 150,
color: Colors.blue,
),
Positioned(
top: 10,
right: 10,
child: buildBadge('NEW'),
),
],
)
35. Complete Profile Card Example
import 'package:flutter/material.dart';
void main() {
runApp(const ProfileApp());
}
class ProfileApp extends StatelessWidget {
const ProfileApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const ProfileScreen(),
);
}
}
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Profile'),
),
body: Center(
child: Card(
margin: const EdgeInsets.all(20),
child: SizedBox(
width: 350,
height: 300,
child: Stack(
children: [
Positioned.fill(
child: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Colors.blue,
Colors.indigo,
],
),
borderRadius: BorderRadius.circular(16),
),
),
),
const Positioned(
top: 30,
left: 0,
right: 0,
child: CircleAvatar(
radius: 50,
child: Icon(
Icons.person,
size: 55,
),
),
),
const Positioned(
top: 145,
left: 0,
right: 0,
child: Text(
'Manish',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
const Positioned(
top: 180,
left: 0,
right: 0,
child: Text(
'Flutter Developer',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white70,
fontSize: 16,
),
),
),
Positioned(
bottom: 25,
left: 30,
right: 30,
child: ElevatedButton(
onPressed: () {},
child: const Text('View Profile'),
),
),
],
),
),
),
),
);
}
}
36. Stack vs Row vs Column
| Widget | Layout Type | Common Use |
| Row | Horizontal | Icons, buttons, horizontal content |
| Column | Vertical | Forms, text sections, vertical content |
| Stack | Layered/overlapping | Overlays, badges, floating elements |
| Positioned | Precise placement inside Stack | Top, bottom, left and right positioning |
37. Stack vs Positioned
| Stack | Positioned |
| Creates a layered layout. | Controls the position of a child inside Stack. |
| Can contain multiple children. | Wraps one child. |
| Controls alignment and overall layering. | Controls top, right, bottom, left, width and height. |
| Can contain positioned and non-positioned children. | Must be used as a descendant of Stack. |
38. Important Stack Rules
- Stack is primarily used for overlapping widgets.
- The order of children controls the painting order.
- The first child is painted at the bottom.
- Later children are painted above earlier children.
- Positioned widgets should be descendants of Stack.
- Non-positioned children contribute to the Stack's size.
- Use
alignment for general alignment of non-positioned children.
- Use
Positioned for explicit placement.
- Use
Positioned.fill for full-area overlays.
- Use
Clip.none when an intentionally positioned element needs to extend outside the Stack.
39. Common Mistakes
Mistake 1: Using Positioned Outside Stack
Column(
children: [
Positioned(
top: 10,
child: Text('Incorrect'),
),
],
)
This is incorrect because Positioned is designed to provide positioning information to a Stack.
Mistake 2: Expecting Stack to Automatically Scroll
Stack itself is not a scrolling widget. If the content needs to scroll, place the appropriate scrollable widget around the layout.
Mistake 3: Excessive Absolute Positioning
Using many hard-coded top and left values can make a UI difficult to maintain across screen sizes. Use responsive constraints and layout widgets where appropriate.
Mistake 4: Forgetting Stack Size
A Stack needs appropriate constraints from its parent. If its size is not determined by its parent or non-positioned children, the resulting layout may not behave as expected.
Mistake 5: Incorrect Layer Order
If a background widget is placed after the foreground widget, it may paint over the foreground. Check the order of children in the Stack.
40. Stack with SafeArea
For interfaces that contain content near system areas such as notches and status bars, SafeArea can be combined with Stack.
Scaffold(
body: SafeArea(
child: Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.blue,
),
),
const Positioned(
top: 20,
left: 20,
child: Text(
'Safe Content',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
],
),
),
)
41. AnimatedPositioned
When a positioned widget needs to move with animation, Flutter provides AnimatedPositioned.
AnimatedPositioned(
duration: const Duration(milliseconds: 500),
left: isExpanded ? 100 : 20,
top: 20,
child: Container(
width: 80,
height: 80,
color: Colors.blue,
),
)
AnimatedPositioned is useful for interactive cards, expandable panels, custom menus, badges, and simple movement animations.
42. Stack in Real-World Applications
- Profile image status indicators
- Notification badges
- Product sale labels
- Image captions
- Image gradients
- Floating action controls
- Video player overlays
- Map markers and overlays
- Custom dashboard cards
- Onboarding screens
- Hero banners
- Decorative UI elements
- Custom loading overlays
- Interactive cards
43. Best Practices
- Use Stack when elements genuinely need to overlap.
- Use Row and Column for normal one-dimensional layouts.
- Use Positioned only when explicit positioning is required.
- Prefer constraints over excessive fixed coordinates.
- Use
Positioned.fill for full-area overlays.
- Use
LayoutBuilder when Stack content needs to adapt to available width.
- Keep the Stack hierarchy simple.
- Use meaningful widget names for complex layered layouts.
- Test positioned layouts on different screen sizes.
- Consider accessibility when placing interactive elements on top of other content.
44. Practice Exercises
- Create a Stack containing three overlapping colored containers.
- Create a profile picture with an online status badge.
- Create a product card with a "20% OFF" badge.
- Create an image banner with text positioned at the bottom.
- Create an image with a dark gradient overlay.
- Create a notification icon with a red count badge.
- Create a Stack with four widgets positioned at its four corners.
- Create a responsive banner using Stack and LayoutBuilder.
- Create an animated badge using AnimatedPositioned.
- Create a profile card using Stack, Positioned, and Positioned.fill.
45. Interview Questions
Q1. What is Stack in Flutter?
Stack is a widget used to position multiple children relative to its box and allows those children to overlap.
Q2. What is Positioned?
Positioned controls the location of a child inside a Stack using properties such as top, right, bottom, left, width, and height.
Q3. Can Positioned be used without Stack?
Positioned is designed to be a descendant of Stack and should not be used as a general-purpose positioning widget outside a Stack.
Q4. What determines the order of layers in Stack?
The order of children in the Stack determines the painting order. Later children are painted above earlier children.
Q5. What is Positioned.fill?
Positioned.fill is a convenient constructor that defaults the left, top, right, and bottom insets to zero, allowing the child to fill the Stack's available area.
Q6. What is the difference between Stack and Column?
Column arranges children vertically, while Stack allows children to overlap and be positioned relative to the Stack.
Q7. What is AnimatedPositioned?
AnimatedPositioned is an animated version of Positioned that transitions position changes over a specified duration.
46. Useful Flutter Documentation
47. Flutter Training Resources
For structured Flutter learning, practical development training, and course information, visit the following resources:
48. Summary
Stack is one of Flutter's most useful widgets for creating layered interfaces. It allows multiple children to overlap, while Positioned provides precise control over where individual children appear within the Stack.
The most important properties of Positioned are top, right, bottom, left, width, and height. Positioned.fill is useful for full-area overlays, while Stack's alignment, fit, and clipBehavior properties provide additional control over the layout.
By combining Stack and Positioned with responsive techniques such as LayoutBuilder, flexible constraints, and appropriate sizing, developers can create professional interfaces such as profile cards, product cards, image banners, notification badges, overlays, and custom dashboard components.
Key Formula: Stack = Layered Layout + Positioned = Precise Placement + Responsive Constraints = Flexible UI