Flutter Overlay: From Basics to Advanced Techniques

Overlays in Flutter are powerful tools that allow developers to display content on top of other widgets in the widget tree. They are commonly used for creating tooltips, context menus, loading indicators, and custom dialogs. In this article, we’ll explore flutter overlay, starting from basic concepts and progressing to more advanced techniques.

Table of Contents

  1. Basic Overlay Example
  2. Intermediate Overlay Example
  3. Advanced Overlay Example

Basic Overlay Example

Let’s start with a simple overlay that displays a loading indicator on top of the current screen.

import 'package:flutter/material.dart';

class BasicOverlayExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Basic Overlay Example')),
      body: Center(
        child: ElevatedButton(
          child: Text('Show Overlay'),
          onPressed: () {
            showLoadingOverlay(context);
          },
        ),
      ),
    );
  }

  void showLoadingOverlay(BuildContext context) {
    OverlayState? overlayState = Overlay.of(context);
    OverlayEntry overlayEntry = OverlayEntry(
      builder: (context) => Center(
        child: CircularProgressIndicator(),
      ),
    );

    overlayState?.insert(overlayEntry);

    // Remove the overlay after 3 seconds
    Future.delayed(Duration(seconds: 3), () {
      overlayEntry.remove();
    });
  }
}

In this basic example, we create a simple loading overlay that appears when a button is pressed and disappears after 3 seconds.

Intermediate Overlay Example

Now, let’s create a more complex overlay that displays a custom tooltip when tapping a button. This example is more suitable for mobile devices.

import 'package:flutter/material.dart';

class IntermediateOverlayExample extends StatefulWidget {
  @override
  _IntermediateOverlayExampleState createState() => _IntermediateOverlayExampleState();
}

class _IntermediateOverlayExampleState extends State<IntermediateOverlayExample> {
  OverlayEntry? _overlayEntry;
  final LayerLink _layerLink = LayerLink();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Intermediate Overlay Example')),
      body: Center(
        child: CompositedTransformTarget(
          link: _layerLink,
          child: ElevatedButton(
            child: Text('Tap for Tooltip'),
            onPressed: () {
              if (_overlayEntry == null) {
                _showTooltip(context);
              } else {
                _hideTooltip();
              }
            },
          ),
        ),
      ),
    );
  }

  void _showTooltip(BuildContext context) {
    _overlayEntry = OverlayEntry(
      builder: (context) => GestureDetector(
        onTap: _hideTooltip,
        behavior: HitTestBehavior.translucent,
        child: Align(
          alignment: Alignment.center,
          child: CompositedTransformFollower(
            link: _layerLink,
            offset: Offset(0, 50),
            child: Material(
              elevation: 4.0,
              borderRadius: BorderRadius.circular(10),
              child: Container(
                padding: EdgeInsets.all(16),
                color: Colors.amber,
                child: Text('This is a custom tooltip!'),
              ),
            ),
          ),
        ),
      ),
    );

    Overlay.of(context)?.insert(_overlayEntry!);
  }

  void _hideTooltip() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  @override
  void dispose() {
    _hideTooltip();
    super.dispose();
  }
}

This intermediate example demonstrates how to create a custom tooltip that appears when tapping a button and disappears when tapping anywhere on the screen. It uses CompositedTransformTarget and CompositedTransformFollower to position the tooltip relative to the button, making it suitable for various screen sizes and orientations.

Advanced Overlay Example

For our advanced example, we’ll create a draggable, resizable overlay window that can be used to display additional content or controls.

import 'package:flutter/material.dart';

class AdvancedOverlayExample extends StatefulWidget {
  @override
  _AdvancedOverlayExampleState createState() => _AdvancedOverlayExampleState();
}

class _AdvancedOverlayExampleState extends State<AdvancedOverlayExample> {
  OverlayEntry? _overlayEntry;
  Offset _offset = Offset(20, 20);
  Size _size = Size(200, 200);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Advanced Overlay Example')),
      body: Center(
        child: ElevatedButton(
          child: Text('Show Draggable Overlay'),
          onPressed: () => _showDraggableOverlay(context),
        ),
      ),
    );
  }

  void _showDraggableOverlay(BuildContext context) {
    _overlayEntry = OverlayEntry(
      builder: (context) => Positioned(
        left: _offset.dx,
        top: _offset.dy,
        child: GestureDetector(
          onPanUpdate: (details) {
            setState(() {
              _offset += details.delta;
              _overlayEntry?.markNeedsBuild();
            });
          },
          child: Material(
            color: Colors.transparent,
            child: Container(
              width: _size.width,
              height: _size.height,
              decoration: BoxDecoration(
                color: Colors.white.withOpacity(0.8),
                borderRadius: BorderRadius.circular(10),
                boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 5)],
              ),
              child: Column(
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      IconButton(
                        icon: Icon(Icons.close),
                        onPressed: _hideOverlay,
                      ),
                      GestureDetector(
                        onPanUpdate: (details) {
                          setState(() {
                            _size = Size(details.delta.dx + _size.width, details.delta.dy + _size.height);
                            _overlayEntry?.markNeedsBuild();
                          });
                        },
                        child: Icon(Icons.drag_handle),
                      ),
                    ],
                  ),
                  Expanded(
                    child: Center(
                      child: Text('Draggable and Resizable Overlay'),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );

    Overlay.of(context)?.insert(_overlayEntry!);
  }

  void _hideOverlay() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  @override
  void dispose() {
    _hideOverlay();
    super.dispose();
  }
}

This advanced example showcases a draggable and resizable overlay window. Users can move the window by dragging it and resize it by dragging the handle in the top-right corner.

Conclusion

Overlays in Flutter provide a powerful way to create dynamic and interactive user interfaces. From simple loading indicators to complex draggable windows, overlays offer flexibility and control over how content is displayed on top of your app’s main UI. As you progress from basic to advanced techniques, you’ll find that overlays can significantly enhance the user experience of your Flutter applications.

Remember to manage your overlays carefully, ensuring they are removed when no longer needed to prevent memory leaks and unexpected behavior. With practice, you’ll be able to create sophisticated and engaging UI elements using Flutter’s overlay system.

Summary
Flutter Overlay: From Basics to Advanced Techniques
Article Name
Flutter Overlay: From Basics to Advanced Techniques
Description
In this article, we'll explore Flutter overlay, starting from basic concepts and progressing to more advanced techniques.
Author
Publisher Name
raheemdev.com
Publisher Logo

Leave a Comment