Flutter覆盖层管理插件flutter_overlay_manager的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter覆盖层管理插件flutter_overlay_manager的使用

flutter_overlay_manager 是一个用于管理Flutter应用中覆盖层(overlay)的插件。它将主UI与覆盖层分离,允许我们在不干扰主UI的情况下添加任何其他图层。这解决了在使用Navigator时遇到的一些问题,如路由管理、生命周期事件处理以及异步操作的复杂性等。

特性

  • 内置加载指示器(loading overlay entry)
  • 支持通过z-index排序
  • 同一ID的覆盖层只会显示一个实例

安装

pubspec.yaml文件中添加依赖:

dependencies:
  flutter_overlay_manager: ^<latest_version>

初始化

作为单例初始化:

FlutterOverlayManager overlayManager = FlutterOverlayManager.I;

或创建新实例:

FlutterOverlayManager overlayManager = FlutterOverlayManager.asNewInstance();

通常在MaterialApp的builder中调用以包裹整个应用程序来管理覆盖层:

MaterialApp(
  builder: (context, child) {
    return FlutterOverlayManager.I.builder((context) => child!);
  },
  home: YourHomePage(),
);

显示自定义覆盖层

可以将任意Widget作为覆盖层显示:

overlayManager.show(
  (context) => YourCustomWidget(),
  id:'your_overlay_entry_id',
  zindex: 1, // 覆盖层的位置
  backgroundColor: Colors.black54,
  dismissible: true,
);

显示加载指示器

内置了加载指示器,用于防止用户在执行API调用或长时间运行任务期间与UI交互。确保任何时候只显示一个加载指示器:

OverlayEntryControl control = await overlayManager.showLoading();
// 或者自定义加载指示器
final control = await FlutterOverlayManager.I.showLoading(builder: (context) => CircularProgressIndicator());

隐藏加载指示器:

control.dismiss(); // 如果有控制引用
// 或者
overlayManager.hide(loadingId); // 如果没有控制引用

设置覆盖层位置

覆盖层的位置由z-index决定,默认情况下加载指示器的z-index为0。例如,要显示一个位于加载指示器之上的覆盖层,可以设置更高的z-index值:

overlayManager.show(
  (context) => const Positioned(
    top: 200,
    right: 0,
    child: TopOverlayView(),
  ),
  zindex: 1, // 加载指示器将在其下方
  id: "_TOP_OVERLAY_ID",
);

隐藏覆盖层

通过ID隐藏特定覆盖层:

overlayManager.hide('your_overlay_id');

或者如果有控制引用,则可以直接调用dismiss()方法。

示例代码

以下是一个完整的示例代码,展示了如何集成和使用flutter_overlay_manager插件。

import 'dart:math';

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

void main() {
  FlutterOverlayManager.I.setLoadingZIndex(0);
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      builder: (context, child) {
        return FlutterOverlayManager.I.builder((context) => child!);
      },
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FilledButton(
              onPressed: () async {
                final loader = await FlutterOverlayManager.I.showLoading();
                await Future.delayed(Duration(seconds: 5));
                await loader.dismiss();
              },
              child: Text("Long-running task"),
            ),
            const SizedBox(height: 32),
            FilledButton(
              onPressed: () {
                if (FlutterOverlayManager.I.isOverlayShowing("_TOP_OVERLAY_ID")) {
                  FlutterOverlayManager.I.hide("_TOP_OVERLAY_ID");
                } else {
                  FlutterOverlayManager.I.show(
                    (context) => const Positioned(
                      top: 200,
                      right: 0,
                      child: TopOverlayView(),
                    ),
                    zindex: 1, // 加载指示器将在其下方
                    id: "_TOP_OVERLAY_ID",
                  );
                }
                setState(() {});
              },
              child: Text(
                  FlutterOverlayManager.I.isOverlayShowing("_TOP_OVERLAY_ID")
                      ? "Hide Top Overlay"
                      : "Show Top Overlay"),
            ),
          ],
        ),
      ),
    );
  }
}

class TopOverlayView extends StatefulWidget {
  const TopOverlayView({super.key});

  @override
  State<TopOverlayView> createState() => _TopOverlayViewState();
}

class _TopOverlayViewState extends State<TopOverlayView> {
  var _color = Colors.yellow;

  void _randomColor() {
    final random = Random();
    _color = Colors.primaries[random.nextInt(Colors.primaries.length)];
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          color: _color,
          width: 50,
          height: 50,
        ),
        const SizedBox(height: 16),
        FilledButton(
          onPressed: () {
            _randomColor();
          },
          child: Text("Click to change color"),
        ),
      ],
    );
  }
}

这个例子展示了如何在一个按钮点击后显示一个长时间运行的任务(模拟为延迟5秒),并在此期间显示加载指示器;另一个按钮用于切换顶部覆盖层的显示/隐藏状态。


更多关于Flutter覆盖层管理插件flutter_overlay_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter覆盖层管理插件flutter_overlay_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 flutter_overlay_manager 插件的示例代码。这个插件允许你更轻松地管理 Flutter 应用中的覆盖层(Overlays)。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_overlay_manager 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_overlay_manager: ^x.y.z  # 替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,你可以在你的 Flutter 应用中使用 flutter_overlay_manager。以下是一个简单的示例,展示如何显示和隐藏一个覆盖层。

主应用代码

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: OverlayManagerProvider(
        child: MyHomePage(),
      ),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  final OverlayManager overlayManager = OverlayManager();

  void _showOverlay() {
    overlayManager.showOverlay(
      context,
      OverlayEntryBuilder(
        builder: (context) {
          return Positioned(
            bottom: 20,
            width: MediaQuery.of(context).size.width,
            child: Container(
              height: 100,
              color: Colors.black54,
              alignment: Alignment.center,
              child: Text('This is an overlay!', style: TextStyle(color: Colors.white)),
            ),
          );
        },
      ),
    );
  }

  void _hideOverlay() {
    overlayManager.hideOverlay(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Overlay Manager Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            ElevatedButton(
              onPressed: _showOverlay,
              child: Text('Show Overlay'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _hideOverlay,
        tooltip: 'Hide Overlay',
        child: Icon(Icons.clear),
      ),
    );
  }
}

解释

  1. 依赖提供:在 MyApp 中,我们使用 OverlayManagerProvider 包裹根组件,以确保 OverlayManager 在整个应用中可用。

  2. OverlayManager 实例:在 MyHomePage 的状态中,我们创建了一个 OverlayManager 实例。

  3. 显示覆盖层:在 _showOverlay 方法中,我们使用 overlayManager.showOverlay 方法显示一个覆盖层。这个覆盖层包含一个 Positioned 组件,它定位在屏幕底部,并包含一个文本。

  4. 隐藏覆盖层:在 _hideOverlay 方法中,我们使用 overlayManager.hideOverlay 方法隐藏当前显示的覆盖层。

  5. UI 组件:在 build 方法中,我们创建了一个简单的 UI,包含一个按钮来显示覆盖层和一个浮动操作按钮来隐藏覆盖层。

这个示例展示了如何使用 flutter_overlay_manager 插件来管理覆盖层。你可以根据需要扩展和修改这个示例以适应你的具体需求。

回到顶部