A flutter widget which renders its child outside the original widget hierarchy.

Overview

overlay_container

Pub Package License

A flutter widget which renders its child outside the original widget hierarchy.

Demo.

Demo

This demo is present as an example here. You can also checkout the examples folder.

Description.

The child passed to this widget is rendered outside the widget hierarchy as an overlay to the exisiting widget tree. As a result this widget is highly suitable for building custom dropdown options, autocomplete suggestions, dialogs, etc. Think of it as widget placed absolutely and having a positive z-index over the rest of the widget tree. It is actually a friendly wrapper over the Flutter's Overlay and OverlayEntry APIs.

If you've ever used react, this tries to do what React Portal does, in a way.

Example.

[ RaisedButton( onPressed: _toggleDropdown, child: Column( children: [ Text("Dropdown button"), ], ), ), // By default the overlay (since this is a Column) will // be added right below the raised button // but outside the widget tree. // We can change that by supplying a "position". OverlayContainer( show: _dropdownShown, // Let's position this overlay to the right of the button. position: OverlayContainerPosition( // Left position. 150, // Bottom position. 45, ), // The content inside the overlay. child: Container( height: 70, padding: const EdgeInsets.all(20), margin: const EdgeInsets.only(top: 5), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey[300], blurRadius: 3, spreadRadius: 6, ) ], ), child: Text("I render outside the \nwidget hierarchy."), ), ), ], ), ), ); } }">
import 'package:flutter/material.dart';
import 'package:overlay_container/overlay_container.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Overlay Container Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // Need to maintain a "show" state either locally or inside
  // a bloc.
  bool _dropdownShown = false;

  void _toggleDropdown() {
    setState(() {
      _dropdownShown = !_dropdownShown;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Overlay Container Demo Page'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            RaisedButton(
              onPressed: _toggleDropdown,
              child: Column(
                children: <Widget>[
                  Text("Dropdown button"),
                ],
              ),
            ),
            // By default the overlay (since this is a Column) will
            // be added right below the raised button
            // but outside the widget tree.
            // We can change that by supplying a "position".
            OverlayContainer(
              show: _dropdownShown,
              // Let's position this overlay to the right of the button.
              position: OverlayContainerPosition(
                // Left position.
                150,
                // Bottom position.
                45,
              ),
              // The content inside the overlay.
              child: Container(
                height: 70,
                padding: const EdgeInsets.all(20),
                margin: const EdgeInsets.only(top: 5),
                decoration: BoxDecoration(
                  color: Colors.white,
                  boxShadow: <BoxShadow>[
                    BoxShadow(
                      color: Colors.grey[300],
                      blurRadius: 3,
                      spreadRadius: 6,
                    )
                  ],
                ),
                child: Text("I render outside the \nwidget hierarchy."),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

A more elaborate example is found here.

Installation.

  • Instructions are here.

Inspiration

License.

Comments
  • Transparent background

    Transparent background

    Hello,

    I am trying to create an overlay with content that isn't square. However, the OverlayContainer seems to have a gray background. Do you have any tips to make it transparent ?

    Thanks in advance :)

    opened by lealouesdon 8
  • Made a CompositedTransformTarget-based derivitive

    Made a CompositedTransformTarget-based derivitive

    Just thought I'd mentioned that I made a derivative widget based on yours to solve some problems I was having (https://github.com/flutter/flutter/issues/19445#issuecomment-570105928)

    Notably I call _overlayEntry.markNeedsBuild(); instead of rebuilding the widget when it's already expanded.

    Might put together an actual PR later also

    opened by micimize 6
  • A few questions

    A few questions

    Hey,

    Thank you for the widget, I always wanted to use Overlays. You've made it so easy that I had to give it a go :)

    I ran into a couple of issues using overlay_container with my custom logic. I've managed to resolve them by changing a few things and I wanted to ask you if I may have missed something.

    1: Why did you decide to put a Future.delayed in your _show method? 2: all WidgetsBinding.instance.addPostFrameCallback are ensured to be executed in the order in which they are called. Is there a reason why you're calling _overlayEntry.remove(); again in show?

    I managed to resolve my issues by changing _show and _hide to:

      void _show() {
        if (!_opened) {
          WidgetsBinding.instance.addPostFrameCallback((_) async {
            _overlayEntry = _buildOverlayEntry();
            Overlay.of(context).insert(_overlayEntry);
            _opened = true;
          });
        }
      }
    
      void _hide() {
        if (_opened) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            _overlayEntry.remove();
            _opened = false;
          });
        }
      }
    

    Am I missing something here?

    opened by modulovalue 1
  • Null Safety here!

    Null Safety here!

    Copy and continue with the rest that is important

    import 'package:flutter/material.dart';
    
    class OverlayContainer extends StatefulWidget {
      /// The child to render inside the container.
      final Widget child;
    
      /// By default, the child will be rendered right below (if the parent is `Column`)
      /// the widget which is defined alongside the OverlayContainer.
      /// It would appear as though the Overlay is inside its parent
      /// but in reality it would be outside and above
      /// the original widget hierarchy.
      /// It's position can be altered and the overlay can
      /// be moved to any part of the screen by supplying a `position`
      /// argument.
      final OverlayContainerPosition position;
    
      /// Controlling whether the overlay is current showing or not.
      final bool show;
    
      /// Whether the overlay is wide as its enclosing parent.
      final bool asWideAsParent;
    
      /// `color` attribute for the `Material` component that wraps `child`.
      final Color materialColor;
    
      const OverlayContainer({
        Key? key,
        required this.show,
        required this.child,
        this.asWideAsParent = false,
        this.position = const OverlayContainerPosition(0.0, 0.0),
        this.materialColor = Colors.transparent,
      }) : super(key: key);
    
      @override
      _OverlayContainerState createState() => _OverlayContainerState();
    }
    
    class _OverlayContainerState extends State<OverlayContainer>
        with WidgetsBindingObserver {
      OverlayEntry? _overlayEntry;
      bool _opened = false;
    
      @override
      void initState() {
        super.initState();
        if (widget.show) {
          _show();
        }
        WidgetsBinding.instance!.addObserver(this);
      }
    
      @override
      void didChangeMetrics() {
        // We would want to re render the overlay if any metrics
        // ever change.
        if (widget.show) {
          _show();
        } else {
          _hide();
        }
      }
    
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        // We would want to re render the overlay if any of the dependencies
        // ever change.
        if (widget.show) {
          _show();
        } else {
          _hide();
        }
      }
    
      @override
      void didUpdateWidget(OverlayContainer oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (widget.show) {
          _show();
        } else {
          _hide();
        }
      }
    
      @override
      void dispose() {
        if (widget.show) {
          _hide();
        }
        WidgetsBinding.instance!.removeObserver(this);
        super.dispose();
      }
    
      void _show() {
        WidgetsBinding.instance!.addPostFrameCallback((_) async {
          await Future.delayed(const Duration(milliseconds: 280));
          if (_opened) {
            _overlayEntry!.remove();
          }
          _overlayEntry = _buildOverlayEntry();
          Overlay.of(context)!.insert(_overlayEntry!);
          _opened = true;
        });
      }
    
      void _hide() {
        if (_opened) {
          WidgetsBinding.instance!.addPostFrameCallback((_) {
            _overlayEntry!.remove();
            _opened = false;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        // Listen to changes in media query such as when a device orientation changes
        // or when the keyboard is toggled.
        MediaQuery.of(context);
        return Container();
      }
    
      OverlayEntry _buildOverlayEntry() {
        RenderBox renderBox = context.findRenderObject() as RenderBox;
        final size = renderBox.size;
        final offset = renderBox.localToGlobal(Offset.zero);
        return OverlayEntry(
          builder: (context) {
            return Positioned(
              left: offset.dx + widget.position.left,
              top: offset.dy - widget.position.bottom,
              width: widget.asWideAsParent ? size.width : null,
              child: Material(
                child: widget.child,
                color: widget.materialColor,
              ),
            );
          },
        );
      }
    }
    
    /// Class to help position the overlay on the screen.
    /// By default it will be rendered right below (if the parent is `Column`)
    /// the widget which is alongside the OverlayContainer.
    /// The Overlay can however be moved around by giving a left value
    /// and a bottom value just like in the case of a `Positioned` widget.
    /// The default values for `left` and `bottom` are 0 and 0 respectively.
    class OverlayContainerPosition {
      final double left;
      final double bottom;
    
      const OverlayContainerPosition(this.left, this.bottom);
    }
    
    
    
    opened by lFitzl 0
  • OverLayContainer dissmiss

    OverLayContainer dissmiss

    Would be great when we click outside the overlay widget the overlayEntry would get removed.

    https://stackoverflow.com/questions/58790406/how-to-close-an-overlay-by-clicking-on-outside-in-flutter

    It is a simple feature although very useful.

    opened by radikris 0
  • When using in Scroll Widget

    When using in Scroll Widget

    When using it in to a scroll widget. the overlay widget will not stick with the parent widget. Once i set show to true, and scroll the screen, the Overlay Container will keep in the same position at i set it show to true. It stick in the position that when i open the overlay. Is there any ways to fix this issue? https://imgur.com/MaXQduB https://imgur.com/x8CyVdw

    opened by 2RocksStudio 0
  • Showing gray screen when app is in release mode

    Showing gray screen when app is in release mode

    Hi ,

    i am using overlay how showing over view for menu tab in flutter web , it works correctly in debug mode , below screenshot is taken when i run flutter in release mode in chrome . gray is the overlay where it should be transparent and able to see letter . but in release mode gray is applying

    please let me know whats the issue .

    image

    opened by VarmaTech 1
Owner
Mustansir Zia
Making/fixing computer things. I develop for web/mobile and desktop.
Mustansir Zia
A Flutter 3D widget that renders Wavefront's object files.

Flutter Cube A Flutter 3D widget that renders Wavefront's object files. Getting Started Add flutter_cube as a dependency in your pubspec.yaml file. de

Zebiao Hu 221 Dec 22, 2022
A simple widget that renders BBCode in Flutter.

A simple display for BBCode in Flutter. Supports custom tags and styles. Features Render BBCode into human readable text. Support for custom tags Prev

Marten 3 Nov 15, 2022
A customizable carousel slider widget in Flutter which supports inifinte scrolling, auto scrolling, custom child widget, custom animations and built-in indicators.

flutter_carousel_widget A customizable carousel slider widget in Flutter. Features Infinite Scroll Custom Child Widget Auto Play Horizontal and Vertic

NIKHIL RAJPUT 7 Nov 26, 2022
This repository contains Collection of UIs made using Flutter. Original Design of all the UIs were created by someone else. I tried to recreate those UIs using Flutter

Flutter-UIs-Collection This repository contains Collection of UIs made using Flutter. Original Design of all the UIs were created by someone else. I t

Mohak Gupta 45 Nov 26, 2022
This is the UI of Furniture App made using Flutter SDK. The original design was made by someone else in dribble and I tried to create the screens of that UI using Flutter

Furniture App - Responsive Flutter UI Watch it on YouTube Responsive UI Fetch Data From API Custom Loading Indicator Packages we are using: flutter_sv

null 6 Dec 3, 2022
Simple & Beautiful App (Tool) made in Flutter to Download Media from YouTube. Based on the original SongTube App repository.

songtube A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

SongTube 11 Dec 18, 2022
Modern implementation of the Original BLoC

stream_bloc Modern implementation of the Original BLoC About This package contai

Yakov Karpov 24 Nov 16, 2022
A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs when current is overscroll, and set scroll direction and cache extent.

extended_tabs Language: English | 中文简体 A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs whe

FlutterCandies 185 Dec 13, 2022
This widget automatically scrolls the custom child widget to an infinite loop.

Scroll Loop Auto Scroll This widget automatically scrolls the custom child widget to an infinite loop. Example Features Infinite Auto Scroll Custom ch

Ashish Raturi 9 Dec 12, 2022
Selectable Circle where colors can be customized and a child widget can be defined

selectable_circle A Flutter package for an Circle that can be Selected with animation. How to use SelectableCircle( width: 80.0, onSelected: (

null 11 Sep 29, 2021
A ListView widget capable of pinning a child to the top of the list.

PinnableListView A Flutter ListView widget that allows pinning a ListView child to the top of the list. Demo Getting Started Define the list PinCont

Jan Hrastnik 2 May 17, 2020
Its a simple app which gives Weather Update, Bit Coin Value Comparator, and Flash Chat Application

Bundle_App_MajorProject Description : Its a simple app which is a bundle of Weather Update App, Bit Coin Value Comparator App, and Flash Chat Applicat

Avinandan Bose 2 Sep 9, 2022
Helper for building advanced multi child layouts.

About Boxy is designed to overcome the limitations of Flutter's built-in layout widgets, it provides utilities for flex, custom multi-child layouts, d

Andre 329 Dec 12, 2022
Declaratively switch child widgets based on the current `Router` location.

Features Declaratively switch child widgets based on the current Router location. class SideBar extends StatelessWidget { Widget build(_){ re

gskinner team 7 Dec 12, 2022
A widget based on Flutter's new Interactive Viewer that makes picture pinch zoom, and return to its initial size and position when released.

pinch_zoom A widget based on Flutter's new Interactive Viewer that makes picture pinch zoom, and return to its initial size and position when released

Teun Kortekaas 36 Dec 30, 2022
This is a project made with Flutter to explore its possibilities and limitations.

persona_builder An application to help you build the perfect persona. Running the application (for web) 1. Prepare environment Make sure you have all

null 0 Dec 24, 2021
its just take image from gallery or camera and save to file (in flutter)

flutter_img_pdf A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started

vivek kumar 0 Dec 28, 2021
A flutter demo app to practice Map data structure and its common operations

Map Operations A flutter demo app to practice Map data structure and its common operations Developer Alexander Sosa (https://www.linkedin.com/in/alexa

Alexander Sosa 0 Jan 3, 2022
A new Flutter project for finding movie and its details

movie_finder A new Flutter project for finding movie and its details. Project Screenshots Home Page Movie Detail Page #Project pages Home Page - Done

ZR Shamim 3 May 22, 2022