Design Overlay component of Flutter suspended UI

Development scenarios often encountered in APP development

Sometimes we encounter the following requirements when developing an APP:

  • Add floating hover buttons, bubbles, or menus to existing pages.
  • Implement a global notification or prompt popup.
  • Create custom navbars, bottom navigation or tab bars.
  • Build modal dialogs or bottom popup menus.
  • Display floating windows on the screen, such as Toast in the Flutter version, PopWindow in any position, etc.
  • Customize Toasts.
  • Float a widget at the top of the page.
    etc.
    These scenarios all have a common feature, that is, a specific UI needs to be displayed in suspension on the current UI. To use flutter to achieve these effects, it is necessary to introduce the Overlay component to be learned today.

Introduction to Overlay

The Overlay component can be used when a new view or interaction needs to be added on top of the existing UI layer in a Flutter application. Overlay allows one or more widgets (called OverlayEntry) to be superimposed on top of the application's existing UI.
Overlay includes two basic components: OverlayState and OverlayEntry. OverlayState manages all OverlayEntry, and OverlayEntry defines the content of the overlay.

Overlay usage rules

  • Create an Overlay object, usually use the Overlay.of(context) method to get the Overlay object in the current context.
  • Creates one or more OverlayEntry objects that will become children of the Overlay.
  • Add OverlayEntry to Overlay, usually use the insert or add method of OverlayEntry.
  • When the overlay needs to be shown or hidden, the OverlayEntry's markNeedsBuild method is called, and the widgets to be displayed are defined in the build method.
    Optional: Control the position and style of the overlay by adjusting the OverlayEntry's position, size, and layout parameters.

for example

The following is a simple example to illustrate: the example is to realize that clicking a button will open the Overlay and display a FloatingActionButton.

source code

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Overlay Example'),
        ),
        body: Center(
          child: ElevatedButton(
            child: Text('Open Overlay'),
            onPressed: () {
              showFloatingButtonOverlay(context);
            },
          ),
        ),
      ),
    );
  }
}

void showFloatingButtonOverlay(BuildContext context) {
  OverlayState? overlayState = Overlay.of(context);
  late OverlayEntry overlayEntry;

  // 创建 OverlayEntry
  overlayEntry = OverlayEntry(
    builder: (BuildContext context) {
      return Positioned(
        top: 100,
        right: 16,
        child: FloatingActionButton(
          onPressed: () {
            // 悬浮按钮被点击
            print('Floating Button Clicked');
            overlayEntry.remove(); // 移除 OverlayEntry
          },
          child: Icon(Icons.add),
        ),
      );
    },
  );

  // 将 OverlayEntry 添加到 Overlay 中
  overlayState?.insert(overlayEntry);
}

The running result is shown in the figure:

Example error

I originally wanted to post the correct code directly, but I think this mistake is easy for beginners to make, so I list it separately.

Error No Overlay widget found

Click the Open Overlay button to report No Overlay widget found. As shown below
image.png

Error reason

The error message is because the Overlay object cannot be found when using the Overlay.of(context) method.

Solution

Make sure the button is in the correct BuildContext object. In the above example, the BuildContext used in the button's onPressed callback should be the context of Scaffold to ensure that the button is defined and used in the correct context.

Make sure the Overlay is properly placed in the application's component tree. In the above example, the Overlay component should be below the MaterialApp or WidgetsApp to ensure they are in the correct hierarchy.

Modified source code

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: OverlayExample(), // 使用 OverlayExample 作为主页
    );
  }
}

class OverlayExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Overlay Example'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Open Overlay'),
          onPressed: () {
            showFloatingButtonOverlay(context);
          },
        ),
      ),
    );
  }
}

void showFloatingButtonOverlay(BuildContext context) {
  OverlayState? overlayState = Overlay.of(context);
  late OverlayEntry overlayEntry;

  // 创建 OverlayEntry
  overlayEntry = OverlayEntry(
    builder: (BuildContext context) {
      return Positioned(
        top: 100,
        right: 16,
        child: FloatingActionButton(
          onPressed: () {
            // 悬浮按钮被点击
            print('Floating Button Clicked');
            overlayEntry.remove(); // 移除 OverlayEntry
          },
          child: Icon(Icons.add),
        ),
      );
    },
  );

  // 将 OverlayEntry 添加到 Overlay 中
  overlayState?.insert(overlayEntry);
}

example effect

The effect of running is shown in the figure:
image.png
the effect picture after clicking the Open Overlay button is as follows:
image.png

Guess you like

Origin blog.csdn.net/yikezhuixun/article/details/131283414