Skip to content

Align

Understand how to position a child within a parent using Align.


What is it?

Align is a widget that positions its child within itself based on alignment values. It allows you to place a child at a specific position (like top-left, center, bottom-right) or at custom fractional positions. Align is simpler than Positioned and is used when you want to position a single child relative to its parent's bounds.


Why does it exist?

Align exists to:

  • Position a child within a parent container
  • Provide simple alignment options
  • Enable fractional positioning
  • Support relative positioning
  • Create responsive layouts
  • Center or offset widgets easily
  • Control child positioning without complex calculations

Basic Align

Align positions a single child within itself.

// Basic Align usage
class BasicAlign extends StatelessWidget {
  const BasicAlign({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      height: 200,
      color: Colors.grey[200],
      child: Align(
        alignment: Alignment.center,
        child: Container(
          width: 50,
          height: 50,
          color: Colors.blue,
        ),
      ),
    );
  }
}

// Align properties:
// 1. alignment - Where to position the child
// 2. child - The widget to position
// 3. widthFactor - Scale child width (optional)
// 4. heightFactor - Scale child height (optional)

What's happening here? - Align positions child within parent - alignment controls position - Child keeps its own size - Parent determines bounds - Simple and predictable


Alignment Values

Different alignment values position the child.

// Alignment values examples
class AlignmentValuesExample extends StatelessWidget {
  const AlignmentValuesExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. Top-left
        _buildAlignWithLabel(
          'Top Left',
          alignment: Alignment.topLeft,
        ),

        // 2. Top-center
        _buildAlignWithLabel(
          'Top Center',
          alignment: Alignment.topCenter,
        ),

        // 3. Top-right
        _buildAlignWithLabel(
          'Top Right',
          alignment: Alignment.topRight,
        ),

        // 4. Center-left
        _buildAlignWithLabel(
          'Center Left',
          alignment: Alignment.centerLeft,
        ),

        // 5. Center
        _buildAlignWithLabel(
          'Center',
          alignment: Alignment.center,
        ),

        // 6. Center-right
        _buildAlignWithLabel(
          'Center Right',
          alignment: Alignment.centerRight,
        ),

        // 7. Bottom-left
        _buildAlignWithLabel(
          'Bottom Left',
          alignment: Alignment.bottomLeft,
        ),

        // 8. Bottom-center
        _buildAlignWithLabel(
          'Bottom Center',
          alignment: Alignment.bottomCenter,
        ),

        // 9. Bottom-right
        _buildAlignWithLabel(
          'Bottom Right',
          alignment: Alignment.bottomRight,
        ),
      ],
    );
  }

  Widget _buildAlignWithLabel(
    String label, {
    required Alignment alignment,
  }) {
    return Container(
      width: 150,
      height: 100,
      color: Colors.grey[200],
      margin: const EdgeInsets.only(bottom: 8),
      child: Stack(
        children: [
          Align(
            alignment: alignment,
            child: Container(
              width: 40,
              height: 30,
              color: Colors.blue,
              child: Center(
                child: Text(
                  label.split(' ').last,
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 10,
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// Standard alignments:
// 1. Alignment.topLeft
// 2. Alignment.topCenter
// 3. Alignment.topRight
// 4. Alignment.centerLeft
// 5. Alignment.center
// 6. Alignment.centerRight
// 7. Alignment.bottomLeft
// 8. Alignment.bottomCenter
// 9. Alignment.bottomRight

What's happening here? - 9 standard alignment positions - Each positions child differently - Child is placed relative to parent - Simple and intuitive


Custom Alignment

Custom alignment values provide precise control.

// Custom alignment examples
class CustomAlignmentExample extends StatelessWidget {
  const CustomAlignmentExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 300,
      color: Colors.grey[200],
      child: Column(
        children: [
          // 1. Fractional alignment (0-1 range)
          Expanded(
            child: Align(
              alignment: const Alignment(0.2, 0.3),
              child: Container(
                width: 50,
                height: 30,
                color: Colors.red,
                child: const Center(
                  child: Text(
                    '0.2,0.3',
                    style: TextStyle(color: Colors.white, fontSize: 10),
                  ),
                ),
              ),
            ),
          ),

          // 2. Negative values
          Expanded(
            child: Align(
              alignment: const Alignment(-0.5, -0.5),
              child: Container(
                width: 50,
                height: 30,
                color: Colors.green,
                child: const Center(
                  child: Text(
                    '-0.5,-0.5',
                    style: TextStyle(color: Colors.white, fontSize: 10),
                  ),
                ),
              ),
            ),
          ),

          // 3. Using AlignmentDirectional
          Expanded(
            child: Align(
              alignment: const AlignmentDirectional(0.8, 0.2),
              child: Container(
                width: 50,
                height: 30,
                color: Colors.blue,
                child: const Center(
                  child: Text(
                    '0.8,0.2',
                    style: TextStyle(color: Colors.white, fontSize: 10),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// Alignment values explained:
// Alignment(0, 0) = center
// Alignment(-1, -1) = top-left
// Alignment(1, 1) = bottom-right
// Alignment(0.5, 0) = center-right
// Values range from -1 to 1
// 0 = center, -1 = start, 1 = end

What's happening here? - Custom values from -1 to 1 - Fine-grained control - Negative values for opposite side - Fractional positioning


Align with Size Factors

WidthFactor and heightFactor scale the child.

// Size factor examples
class SizeFactorExample extends StatelessWidget {
  const SizeFactorExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 200,
      color: Colors.grey[200],
      child: Column(
        children: [
          // 1. No factor (child keeps size)
          Expanded(
            child: Align(
              alignment: Alignment.center,
              child: Container(
                color: Colors.red,
                child: const Text('No Factor'),
              ),
            ),
          ),

          // 2. Width factor 0.5 (child takes half width)
          Expanded(
            child: Align(
              alignment: Alignment.center,
              widthFactor: 0.5,
              child: Container(
                color: Colors.green,
                child: const Text('Width 0.5'),
              ),
            ),
          ),

          // 3. Both factors (child scales)
          Expanded(
            child: Align(
              alignment: Alignment.center,
              widthFactor: 0.5,
              heightFactor: 0.5,
              child: Container(
                color: Colors.blue,
                child: const Text('Both 0.5'),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// Size factor effects:
// widthFactor: null (use child width)
// widthFactor: 0.5 (child width = 50% of parent)
// widthFactor: 1.0 (child fills parent width)
// heightFactor: null (use child height)
// heightFactor: 0.5 (child height = 50% of parent)
// heightFactor: 1.0 (child fills parent height)

What's happening here? - widthFactor scales child width - heightFactor scales child height - Null uses child's own size - 1.0 fills parent dimension - Useful for responsive sizing


Align vs Other Positioning

Comparing Align with similar widgets.

// Align vs Container alignment
class AlignmentComparison extends StatelessWidget {
  const AlignmentComparison({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. Align widget
        Container(
          width: 200,
          height: 100,
          color: Colors.grey[200],
          child: Align(
            alignment: Alignment.center,
            child: Container(
              width: 50,
              height: 30,
              color: Colors.blue,
            ),
          ),
        ),

        const SizedBox(height: 10),

        // 2. Container alignment
        Container(
          width: 200,
          height: 100,
          color: Colors.grey[200],
          alignment: Alignment.center,
          child: Container(
            width: 50,
            height: 30,
            color: Colors.green,
          ),
        ),

        const SizedBox(height: 10),

        // 3. Center widget
        Container(
          width: 200,
          height: 100,
          color: Colors.grey[200],
          child: Center(
            child: Container(
              width: 50,
              height: 30,
              color: Colors.red,
            ),
          ),
        ),
      ],
    );
  }
}

// When to use each:
// Align: Any alignment, fractional positioning
// Center: Only centering (simpler)
// Container.alignment: Built-in alignment
// Positioned: Only in Stack

What's happening here? - Align: flexible alignment - Container.alignment: built-in - Center: simple centering - Each has different use cases


Real-World Examples

Common patterns using Align.

// 1. Badge on widget
class BadgeWithAlign extends StatelessWidget {
  const BadgeWithAlign({
    super.key,
    required this.child,
    required this.count,
  });

  final Widget child;
  final int count;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        child,
        Positioned(
          top: 0,
          right: 0,
          child: Align(
            alignment: Alignment.topRight,
            child: Container(
              padding: const EdgeInsets.all(4),
              decoration: const BoxDecoration(
                color: Colors.red,
                shape: BoxShape.circle,
              ),
              child: Text(
                count > 99 ? '99+' : count.toString(),
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 10,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

// 2. Floating action button with alignment
class FloatingActionWithAlign extends StatelessWidget {
  const FloatingActionWithAlign({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          // Content
          Container(color: Colors.grey[200]),

          // FAB positioned with Align
          Align(
            alignment: Alignment.bottomRight,
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Container(
                width: 56,
                height: 56,
                decoration: const BoxDecoration(
                  color: Colors.blue,
                  shape: BoxShape.circle,
                ),
                child: const Icon(
                  Icons.add,
                  color: Colors.white,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// 3. Logo with text overlay
class LogoWithOverlay extends StatelessWidget {
  const LogoWithOverlay({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      height: 200,
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(16),
        image: const DecorationImage(
          image: NetworkImage('https://example.com/logo.jpg'),
          fit: BoxFit.cover,
        ),
      ),
      child: Align(
        alignment: Alignment.bottomCenter,
        child: Container(
          width: double.infinity,
          padding: const EdgeInsets.all(8),
          color: Colors.black.withOpacity(0.7),
          child: const Text(
            'Logo Text',
            style: TextStyle(
              color: Colors.white,
              fontSize: 16,
              fontWeight: FontWeight.bold,
            ),
            textAlign: TextAlign.center,
          ),
        ),
      ),
    );
  }
}

// 4. Responsive positioning
class ResponsivePosition extends StatelessWidget {
  const ResponsivePosition({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // Adjust alignment based on screen size
        final isLarge = constraints.maxWidth > 600;

        return Container(
          width: double.infinity,
          height: 200,
          color: Colors.grey[200],
          child: Align(
            alignment: isLarge 
                ? Alignment.centerRight 
                : Alignment.center,
            child: Container(
              padding: const EdgeInsets.all(16),
              color: Colors.blue,
              child: Text(
                isLarge ? 'Large Screen' : 'Small Screen',
                style: const TextStyle(color: Colors.white),
              ),
            ),
          ),
        );
      },
    );
  }
}

What's happening here? - Badge positioned with Align - Floating action button - Image overlay with text - Responsive positioning


Best Practices

Use Align for Single Child Positioning

// Good - Using Align
@override
Widget build(BuildContext context) {
  return Container(
    child: Align(
      alignment: Alignment.center,
      child: const Text('Positioned'),
    ),
  );
}

Use Alignment Values

// Good - Using standard alignments
@override
Widget build(BuildContext context) {
  return Align(
    alignment: Alignment.topRight,
    child: child,
  );
}

Use Size Factors for Responsive Sizing

// Good - Responsive sizing
@override
Widget build(BuildContext context) {
  return Align(
    alignment: Alignment.center,
    widthFactor: 0.8, // 80% of parent width
    child: Container(
      color: Colors.blue,
      child: const Text('Responsive'),
    ),
  );
}

Common Mistakes

Overusing Positioned

Wrong:

// Using Positioned outside Stack
Positioned(
  top: 20,
  left: 20,
  child: const Text('Error'),
)

Correct:

// Use Align for simple positioning
Align(
  alignment: Alignment.topLeft,
  child: const Text('Correct'),
)

Wrong Alignment Values

Wrong:

// Values outside -1 to 1 range
Align(
  alignment: Alignment(2, 2), // Invalid
  child: child,
)

Correct:

// Values within -1 to 1 range
Align(
  alignment: Alignment(0.5, 0.5),
  child: child,
)


Summary

Align positions a child within a parent using alignment values. It provides 9 standard positions and custom fractional positioning. Use Align for simple positioning, responsive layouts, and when you need to place a child relative to its parent's bounds.


Next Steps


Did You Know?

  • Align positions relative to parent bounds
  • Alignment values range from -1 to 1
  • widthFactor and heightFactor scale child size
  • Align is simpler than Positioned
  • Container.alignment uses the same system
  • Align works with any child widget
  • Align supports RTL layouts
  • Align is used in many Flutter widgets