On this page19 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. Stack — Layers on Top of Each Other
  5. 2. alignment
  6. 3. Positioned — Pin a Child to the Edges
  7. 4. Stretching Between Two Edges
  8. 5. Positioned.fill
  9. 6. Children That Stick Out
  10. 7. A Real-World Example
  11. Code Examples
  12. Common Beginner Mistakes
  13. Best Practices
  14. Mini Challenge
  15. Practice Questions
  16. Practice Answers
  17. Quick Revision
  18. Key Takeaways
  19. What's Next?

Lecture 005 — Stack & Positioned

Category2 — Layout Widgets
Lecture005 of 009
Estimated video length14 min
TargetFlutter 3.44 · Dart 3.12
LevelBeginner

Row and Column can only put widgets next to each other. A red badge on a cart icon, text over a banner, an avatar overlapping a cover — these need widgets on top of each other, and that is what Stack and Positioned do.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every screenshot and error message in this lecture is real. Each app was run on Flutter 3.44, and each error was produced by the code shown.


Prerequisites

Students should already understand, from Lectures 001–004:

  • Container, BoxDecoration, circles, gradients and TextStyle
  • Align/Alignment, SizedBox and AspectRatio
  • Row, Column, Expanded and double.infinity

Connection With Previous Lectures

Picture a shopping app's product card: a picture, a red SALE label in its top-left corner, a heart in its top-right corner and the price along the bottom — all drawn over the picture. With a Column, the label would sit above the picture and the price below it, never on it. We need a layout where children share the same space and are painted one over another.


Learning Objectives

By the end of this lecture you will be able to:

  • Layer widgets with Stack and explain the order they are painted in
  • Align all unpositioned children with Stack's alignment
  • Pin a child to the edges with Positioned (top, left, right, bottom)
  • Stretch a child between two edges, or over the whole Stack with Positioned.fill
  • Let children stick out of a Stack with clipBehavior: Clip.none
  • Build badges, overlays and overlapping avatars
  • Recognize the error for a Positioned outside a Stack

1. Stack — Layers on Top of Each Other

Stack takes children like a Column, but it puts them all in the same place. The first child is painted first, at the bottom; each later child is painted on top:

dart
body: Stack(
  children: [
    Container(width: 200, height: 200, color: Colors.red.shade200),
    Container(width: 140, height: 140, color: Colors.green.shade200),
    Container(width: 80, height: 80, color: Colors.blue.shade200),
  ],
),
A red, a green and a blue square stacked at the top-left, smallest on top
Three Containers in a Stack

Analogy — a Stack is a pile of paper on a desk. The first sheet is at the bottom; every new sheet goes on top and covers part of what is below.

By default every child starts at the top-left corner. The Stack itself is as big as its biggest child — here the 200 × 200 red square.


2. alignment

alignment moves all the children (except Positioned ones) to the same point:

dart
body: Stack(
  alignment: Alignment.center,
  children: [
    Container(width: 200, height: 200, color: Colors.red.shade200),
    Container(width: 140, height: 140, color: Colors.green.shade200),
    Container(width: 80, height: 80, color: Colors.blue.shade200),
  ],
),
The three squares centered on each other like a target
Stack(alignment: Alignment.center)

It takes the same Alignment values as Align: Alignment.bottomRight would line the squares up on their bottom-right corners.


3. Positioned — Pin a Child to the Edges

Positioned places one child at a distance from the Stack's edges:

dart
body: SizedBox(
  width: double.infinity,
  height: 240,
  child: Stack(
    children: [
      Container(color: Colors.grey.shade200),
      const Positioned(
        top: 16,
        left: 16,
        child: Text('top: 16, left: 16'),
      ),
      const Positioned(
        bottom: 16,
        right: 16,
        child: Text('bottom: 16, right: 16'),
      ),
      Positioned(
        top: 80,
        left: 120,
        child: Container(width: 60, height: 60, color: Colors.orange),
      ),
    ],
  ),
),
A grey area with text at the top-left, text at the bottom-right and an orange square inside
Positioned with top, left, bottom and right
  • top: 16, left: 16 — 16 pixels from the top edge and the left edge.
  • bottom: 16, right: 16 — measured from the bottom-right corner instead.
  • A Positioned child does not affect the Stack's size. That is why the Stack needs a size from somewhere — here a SizedBox, and the grey Container fills it.

4. Stretching Between Two Edges

Give both left and right and the child's width is decided for you — everything between the two distances:

dart
body: SizedBox(
  width: double.infinity,
  height: 240,
  child: Stack(
    children: [
      Container(color: Colors.grey.shade200),
      Positioned(
        left: 24,
        right: 24,
        bottom: 24,
        child: Container(
          height: 50,
          color: Colors.indigo,
          alignment: Alignment.center,
          child: const Text(
            'left: 24, right: 24 — no width needed',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    ],
  ),
),
An indigo bar along the bottom with 24-pixel gaps at the left, right and bottom
left and right together set the width

The same works vertically with top and bottom. Of left, right and width you may give any two; the third is calculated.


5. Positioned.fill

Positioned.fill sets all four edges to 0, so the child covers the whole Stack. It is the standard way to lay a dark, see-through layer over a picture so white text on it stays readable:

dart
body: Padding(
  padding: const EdgeInsets.all(16),
  child: SizedBox(
    height: 200,
    child: Stack(
      children: [
        Container(color: Colors.teal),
        Positioned.fill(
          child: Container(
            color: Colors.black.withValues(alpha: 0.4),
            alignment: Alignment.center,
            child: const Text(
              'A dark layer over the whole Stack',
              style: TextStyle(color: Colors.white, fontSize: 18),
            ),
          ),
        ),
      ],
    ),
  ),
),
A dark teal box with white text in the middle
A 40 % black layer over the teal Container

6. Children That Stick Out

A badge usually hangs over the corner of its icon. Negative distances move a child outside the Stack — but by default the Stack cuts off anything outside its edges:

dart
body: Center(
  child: Stack(
    children: [
      Container(width: 120, height: 120, color: Colors.indigo.shade100),
      Positioned(
        top: -10,
        right: -10,
        child: Container(
          width: 36,
          height: 36,
          alignment: Alignment.center,
          decoration: const BoxDecoration(
            color: Colors.red,
            shape: BoxShape.circle,
          ),
          child: const Text('5', style: TextStyle(color: Colors.white)),
        ),
      ),
    ],
  ),
),
A lavender square with a red badge cut into a quarter circle at its corner
The badge is clipped

clipBehavior: Clip.none turns the clipping off:

dart
body: Center(
  child: Stack(
    clipBehavior: Clip.none,
    children: [
      Container(width: 120, height: 120, color: Colors.indigo.shade100),
      Positioned(
        top: -10,
        right: -10,
        child: Container(
          width: 36,
          height: 36,
          alignment: Alignment.center,
          decoration: const BoxDecoration(
            color: Colors.red,
            shape: BoxShape.circle,
          ),
          child: const Text('5', style: TextStyle(color: Colors.white)),
        ),
      ),
    ],
  ),
),
The same square with a full red circle badge overlapping its top-right corner
clipBehavior: Clip.none

7. A Real-World Example

The product card from the start of the lecture. A gradient stands in for the product photo — in Lecture 006 we will put a real image there.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.pink),
      home: const ProductScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    String product = 'Wireless Headphones';
    int price = 4500;
    int salePrice = 3600;

    return Scaffold(
      appBar: AppBar(title: const Text('Shop')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: AspectRatio(
          aspectRatio: 1,
          child: Stack(
            children: [
              Container(
                decoration: BoxDecoration(
                  gradient: const LinearGradient(
                    colors: [Color(0xFFF8BBD0), Color(0xFFCE93D8)],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                  borderRadius: BorderRadius.circular(20),
                ),
              ),
              Positioned(
                top: 16,
                left: 16,
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 4,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.red,
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: const Text(
                    'SALE',
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
              const Positioned(
                top: 12,
                right: 12,
                child: Icon(Icons.favorite_border, size: 30),
              ),
              Positioned(
                left: 0,
                right: 0,
                bottom: 0,
                child: Container(
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: Colors.white.withValues(alpha: 0.85),
                    borderRadius: const BorderRadius.vertical(
                      bottom: Radius.circular(20),
                    ),
                  ),
                  child: Row(
                    children: [
                      Expanded(
                        child: Text(
                          product,
                          style: const TextStyle(fontWeight: FontWeight.w600),
                        ),
                      ),
                      Text(
                        'Rs. $price',
                        style: const TextStyle(
                          color: Colors.grey,
                          decoration: TextDecoration.lineThrough,
                        ),
                      ),
                      const SizedBox(width: 8),
                      Text(
                        'Rs. $salePrice',
                        style: const TextStyle(
                          color: Colors.red,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A pink-purple square card with a red SALE label top-left, a heart outline top-right and a white strip at the bottom with the name, a crossed-out Rs. 4500 and a red Rs. 3600
Product card

New details:

  • BorderRadius.vertical(bottom: Radius.circular(20)) rounds only the two bottom corners, so the white strip fits the card's corners.
  • TextDecoration.lineThrough crosses out the old price.
  • The bottom strip is a Positioned with left: 0, right: 0, bottom: 0 — full width, stuck to the bottom — and inside it a normal Row with Expanded. Layout widgets mix freely.

Code Examples

Example 1 — Text on a Circle

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Example 1')),
      body: Center(
        child: Stack(
          alignment: Alignment.center,
          children: [
            Container(
              width: 160,
              height: 160,
              decoration: const BoxDecoration(
                color: Colors.amber,
                shape: BoxShape.circle,
              ),
            ),
            const Text(
              'Ali',
              style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}
Ali in large bold letters on an amber circle
Example 1

Example 2 — Four Corners and the Center

Center is not Positioned, so it is laid out over the whole Stack like any other child.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Example 2')),
      body: SizedBox(
        width: double.infinity,
        height: 200,
        child: Stack(
          children: [
            Container(color: Colors.blueGrey.shade100),
            const Positioned(top: 8, left: 8, child: Text('top left')),
            const Positioned(top: 8, right: 8, child: Text('top right')),
            const Positioned(bottom: 8, left: 8, child: Text('bottom left')),
            const Positioned(bottom: 8, right: 8, child: Text('bottom right')),
            const Center(child: Text('center')),
          ],
        ),
      ),
    );
  }
}
Labels in all four corners of a grey area and center in the middle
Example 2

Example 3 — Notification Badge

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Notifications')),
      body: Center(
        child: Stack(
          clipBehavior: Clip.none,
          children: [
            const Icon(Icons.notifications, size: 56),
            Positioned(
              top: -4,
              right: -4,
              child: Container(
                padding: const EdgeInsets.all(6),
                decoration: const BoxDecoration(
                  color: Colors.red,
                  shape: BoxShape.circle,
                ),
                child: const Text(
                  '12',
                  style: TextStyle(color: Colors.white, fontSize: 12),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
A bell icon with a small red 12 badge on its corner
Example 3

Example 4 — Course Banner

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.deepPurple),
      home: const BannerScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Course')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: AspectRatio(
          aspectRatio: 16 / 9,
          child: Stack(
            children: [
              Positioned.fill(
                child: Container(
                  decoration: BoxDecoration(
                    gradient: const LinearGradient(
                      colors: [Colors.deepPurple, Colors.blue],
                    ),
                    borderRadius: BorderRadius.circular(16),
                  ),
                ),
              ),
              const Positioned(
                left: 20,
                bottom: 20,
                right: 20,
                child: Text(
                  'Flutter Essential Widgets\n9 lectures · 3 hours',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 22,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
              const Positioned(
                top: 12,
                right: 12,
                child: Icon(
                  Icons.play_circle_fill,
                  color: Colors.white,
                  size: 40,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A purple-to-blue banner with the course name at the bottom-left and a play icon top-right
Example 4

Example 5 — Debit Card

Five layers: the card, a chip, a label, the owner's name and the balance.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const CardScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    String owner = 'Zayan';
    double balance = 25000;

    return Scaffold(
      appBar: AppBar(title: const Text('Debit Card')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: AspectRatio(
          aspectRatio: 1.6,
          child: Stack(
            children: [
              Positioned.fill(
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.indigo.shade900,
                    borderRadius: BorderRadius.circular(20),
                  ),
                ),
              ),
              Positioned(
                top: 24,
                left: 24,
                child: Container(
                  width: 44,
                  height: 32,
                  decoration: BoxDecoration(
                    color: Colors.amber.shade300,
                    borderRadius: BorderRadius.circular(6),
                  ),
                ),
              ),
              const Positioned(
                top: 24,
                right: 24,
                child: Text(
                  'DEBIT',
                  style: TextStyle(color: Colors.white70, letterSpacing: 2),
                ),
              ),
              Positioned(
                left: 24,
                bottom: 24,
                child: Text(
                  owner,
                  style: const TextStyle(color: Colors.white, fontSize: 18),
                ),
              ),
              Positioned(
                right: 24,
                bottom: 24,
                child: Text(
                  'Rs. $balance',
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A dark blue card with a gold chip, DEBIT, Zayan and Rs. 25000.0
Example 5

Example 6 — Overlapping Circles

The second circle is 80 % opaque, so the first one shows through where they overlap.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Example 6')),
      body: Center(
        child: SizedBox(
          width: 220,
          height: 120,
          child: Stack(
            children: [
              Positioned(
                left: 0,
                child: Container(
                  width: 120,
                  height: 120,
                  decoration: const BoxDecoration(
                    color: Colors.red,
                    shape: BoxShape.circle,
                  ),
                ),
              ),
              Positioned(
                right: 0,
                child: Container(
                  width: 120,
                  height: 120,
                  decoration: BoxDecoration(
                    color: Colors.amber.withValues(alpha: 0.8),
                    shape: BoxShape.circle,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A red circle overlapped by a semi-transparent amber circle
Example 6

Common Beginner Mistakes

1. Positioned outside a Stack

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Oops')),
      body: const Column(
        children: [Positioned(top: 20, left: 20, child: Text('Where am I?'))],
      ),
    );
  }
}
The text Where am I? at the top-left, ignoring top and left
The positions are ignored
output
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞════════════════════════
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Positioned(left: 20.0, top: 20.0) wants to
apply ParentData of type StackParentData to a RenderObject, which
has been set up to accept ParentData of incompatible type
FlexParentData.
Usually, this means that the Positioned widget has the wrong
ancestor RenderObjectWidget. Typically, Positioned widgets are
placed directly inside Stack widgets.
The offending Positioned is currently placed inside a Column

Positioned only works as a direct child of a Stack — just like Expanded only works in a Row or Column.

2. Too many values on one axis

dart
import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      home: Scaffold(
        body: Stack(
          children: [
            Positioned(top: 0, bottom: 0, height: 100, child: Text('Ali')),
          ],
        ),
      ),
    ),
  );
}
output
error • Evaluation of this constant expression throws an exception • lib/main.dart:9:13 • const_eval_throws_exception

top, bottom and height describe the same direction; three values can contradict each other, so Flutter accepts at most two. The same goes for left, right and width.

3. A Stack with only Positioned children

Positioned children do not give a Stack its size. If every child is Positioned, the Stack takes the biggest size it is allowed and your children may end up somewhere unexpected. Give it a size with a SizedBox, an AspectRatio, or one normal child, as all the examples do.

4. A badge cut in half

The Stack clips by default (section 6). Add clipBehavior: Clip.none.


Best Practices

  • Use a Stack only for real overlap. If things sit next to each other, a Row or Column is simpler and adapts better.
  • Give every Stack a clear size: a sized background child, a SizedBox or an AspectRatio.
  • Put a dark see-through layer (Positioned.fill) under white text on pictures or bright gradients.
  • Prefer left + right over a fixed width for bars and captions, so they fit every screen.
  • Keep the painting order in mind: background first, badges and captions last.

Mini Challenge

Build a weather banner for Lahore: a 16 : 9 card with an orange-to-deep-orange diagonal gradient and 20-pixel rounded corners, with:

  • Lahore (white, 20 pixels) in the top-left corner
  • a white rounded Sunny chip in the top-right corner
  • 30°C (white, 56 pixels, bold) in the bottom-left corner

Try it yourself before opening the solution.

Show solution
dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.orange),
      home: const WeatherScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Weather')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: AspectRatio(
          aspectRatio: 16 / 9,
          child: Stack(
            children: [
              Positioned.fill(
                child: Container(
                  decoration: BoxDecoration(
                    gradient: const LinearGradient(
                      colors: [Colors.orange, Colors.deepOrange],
                      begin: Alignment.topLeft,
                      end: Alignment.bottomRight,
                    ),
                    borderRadius: BorderRadius.circular(20),
                  ),
                ),
              ),
              const Positioned(
                top: 20,
                left: 20,
                child: Text(
                  'Lahore',
                  style: TextStyle(color: Colors.white, fontSize: 20),
                ),
              ),
              Positioned(
                top: 16,
                right: 16,
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 12,
                    vertical: 4,
                  ),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: const Text('Sunny'),
                ),
              ),
              const Positioned(
                left: 20,
                bottom: 12,
                child: Text(
                  '30°C',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 56,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
An orange gradient card with Lahore top-left, a white Sunny chip top-right and a large 30°C bottom-left
Mini challenge solution

How it works

  1. AspectRatio gives the Stack its size; Positioned.fill makes the gradient cover it.
  2. Each label is a Positioned measured from the nearest corner.
  3. The chip is a Container with padding and a large borderRadius — a pill shape.

Practice Questions

Beginner

  1. Stack a 100 × 100 yellow square on a 200 × 200 blue square.
  2. Do the same, but line both squares up on their bottom-right corners.
  3. In a full-width, 200-pixel-tall light-green area, show Hello, Sara 20 pixels from the top and the left.

Application

  1. Over a 180-pixel-tall purple box, lay a 50 % black layer with the white 24-pixel text Coming soon in the center.
  2. Draw Sara's 100 × 100 indigo avatar with a white S, and a green "online" dot with a white border at its bottom-right.
  3. Build a 140-pixel light-blue rounded card with Karachi at the top-left and a bold, 44-pixel 34°C at the bottom-right.
  4. Put a red 3 badge on Icons.shopping_cart (size 56), overlapping its corner.

Challenge

  1. Build Zayan's profile header: a 160-pixel teal-to-green cover, a 100 × 100 avatar circle with a white border that hangs halfway below the cover, and under it his name and Flutter student.

Practice Answers

Question 1 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 1')),
      body: Stack(
        children: [
          Container(width: 200, height: 200, color: Colors.blue),
          Container(width: 100, height: 100, color: Colors.yellow),
        ],
      ),
    );
  }
}
A yellow square on the top-left of a larger blue square
Question 1

Question 2 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 2')),
      body: Stack(
        alignment: Alignment.bottomRight,
        children: [
          Container(width: 200, height: 200, color: Colors.blue),
          Container(width: 100, height: 100, color: Colors.yellow),
        ],
      ),
    );
  }
}
A yellow square in the bottom-right of a blue square
Question 2

Question 3 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 3')),
      body: SizedBox(
        width: double.infinity,
        height: 200,
        child: Stack(
          children: [
            Container(color: Colors.green.shade100),
            const Positioned(top: 20, left: 20, child: Text('Hello, Sara')),
          ],
        ),
      ),
    );
  }
}
Hello, Sara near the top-left of a light-green area
Question 3

Question 4 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 4')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: SizedBox(
          height: 180,
          child: Stack(
            children: [
              Container(color: Colors.purple),
              Positioned.fill(
                child: Container(
                  color: Colors.black.withValues(alpha: 0.5),
                  alignment: Alignment.center,
                  child: const Text(
                    'Coming soon',
                    style: TextStyle(color: Colors.white, fontSize: 24),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A dark purple box with Coming soon in white
Question 4

Question 5 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 5')),
      body: Center(
        child: Stack(
          children: [
            Container(
              width: 100,
              height: 100,
              alignment: Alignment.center,
              decoration: const BoxDecoration(
                color: Colors.indigo,
                shape: BoxShape.circle,
              ),
              child: const Text(
                'S',
                style: TextStyle(color: Colors.white, fontSize: 40),
              ),
            ),
            Positioned(
              right: 4,
              bottom: 4,
              child: Container(
                width: 22,
                height: 22,
                decoration: BoxDecoration(
                  color: Colors.green,
                  shape: BoxShape.circle,
                  border: Border.all(color: Colors.white, width: 3),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
An indigo S avatar with a green dot at its bottom-right
Question 5

Question 6 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 6')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: SizedBox(
          height: 140,
          child: Stack(
            children: [
              Positioned.fill(
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.lightBlue.shade100,
                    borderRadius: BorderRadius.circular(16),
                  ),
                ),
              ),
              const Positioned(
                top: 16,
                left: 16,
                child: Text('Karachi', style: TextStyle(fontSize: 18)),
              ),
              const Positioned(
                right: 16,
                bottom: 8,
                child: Text(
                  '34°C',
                  style: TextStyle(fontSize: 44, fontWeight: FontWeight.bold),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
A light-blue card with Karachi top-left and 34°C bottom-right
Question 6

Question 7 — Solution

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: const HomeScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Question 7')),
      body: Center(
        child: Stack(
          clipBehavior: Clip.none,
          children: [
            const Icon(Icons.shopping_cart, size: 56),
            Positioned(
              top: -6,
              right: -6,
              child: Container(
                width: 24,
                height: 24,
                alignment: Alignment.center,
                decoration: const BoxDecoration(
                  color: Colors.red,
                  shape: BoxShape.circle,
                ),
                child: const Text('3', style: TextStyle(color: Colors.white)),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
A cart icon with a red 3 badge
Question 7

Question 8 — Solution

bottom: -50 moves the 100-pixel avatar half outside the Stack, so clipBehavior: Clip.none is needed. The Stack is still only as tall as the cover, so the Column adds a 60-pixel gap before the name to make room for the hanging half.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: Colors.teal),
      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: Column(
        children: [
          Stack(
            clipBehavior: Clip.none,
            alignment: Alignment.bottomCenter,
            children: [
              Container(
                height: 160,
                decoration: const BoxDecoration(
                  gradient: LinearGradient(colors: [Colors.teal, Colors.green]),
                ),
              ),
              Positioned(
                bottom: -50,
                child: Container(
                  width: 100,
                  height: 100,
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: Colors.teal.shade700,
                    shape: BoxShape.circle,
                    border: Border.all(color: Colors.white, width: 4),
                  ),
                  child: const Text(
                    'Z',
                    style: TextStyle(color: Colors.white, fontSize: 40),
                  ),
                ),
              ),
            ],
          ),
          const SizedBox(height: 60),
          const Text(
            'Zayan',
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
          const Text('Flutter student'),
        ],
      ),
    );
  }
}
A teal-green cover with a Z avatar overlapping its bottom edge, and Zayan, Flutter student below
Question 8

Quick Revision

  1. Which child of a Stack is painted on top?
  2. How big is a Stack whose children are not Positioned?
  3. What does Stack's alignment affect?
  4. What do left: 0, right: 0 do to a Positioned child?
  5. What is Positioned.fill short for?
  6. Why might a badge with top: -10 be cut off, and how do you fix it?
  7. Where must a Positioned widget be placed?
  8. How many of top, bottom and height can you give at once?

Key Takeaways

  • Stack layers its children in the same space; later children are painted on top.
  • Unpositioned children follow the Stack's alignment, and decide its size.
  • Positioned pins a child by distances from the edges; two opposite edges set the size.
  • Positioned.fill covers the whole Stack — ideal for dark overlays.
  • clipBehavior: Clip.none lets badges and avatars stick out.
  • Positioned must be a direct child of a Stack.

What's Next?

Lecture 006 — Images, Icons & Buttons. Our cards use gradients where pictures should be, and our buttons do nothing. Next we show real images from the app and the internet, use the full Material icon set, and build every kind of button — and make them react when tapped.