Flutter 全局悬浮控件(Overlay顶层视图)

4,852 阅读2分钟

在平常的需求开发中,可能会遇到需要在app中添加一个全局的视图,比如单点登录提示的全局弹框,音乐播放的悬浮控制按钮等。简单看了下在Flutter中的实现思路,记录一下。

这篇文章拿稍微复杂一点的音乐播放悬浮控制按钮作为实现示例,主要内容包含两点:

1.顶层视图的显示

2.组件拖动+两侧吸附效果

1.顶层视图显示

在flutter中实现顶层视图显示,是通过Overlay这个组件来实现的,这个组件的官方解释如下(仔细看官方解释,真的很重要,尤其是最后一句):

/// A [Stack] of entries that can be managed independently.
///
/// Overlays let independent child widgets "float" visual elements on top of
/// other widgets by inserting them into the overlay's [Stack]. The overlay lets
/// each of these widgets manage their participation in the overlay using
/// [OverlayEntry] objects.
/// Rather than creating an overlay, consider using the overlay that is
/// created by the [WidgetsApp] or the [MaterialApp] for the application.

Overlay的本质是“float(悬浮)”在其他组件上的Stack(组件的本质是Stack,所以我们想要添加的全局组件,就可以通过Position()控制位置啦(* ̄︶ ̄)),这个Stack可添加的子组件只能是OverlayEntry类型,所以当我们想要创建一个悬浮在全局的组件时,我们应该想办法拿到Overlay组件的实例,然后创建OverlayEntry,添加进Overlay

那该怎么获取Overlay呢,最开始我以为可以通过Overlay.of(context)方法获取,但是我用这种方法获取之后,发现当我退出创建此悬浮组件的页面时,此context也会销毁,所以此方法不可取(哎……其实就是没有仔细看官方的解释,上面解释中的最后一句,已经给出答案(⊙︿⊙))。官方文档已经说了,最好使用WidgetsApp或MaterialApp的Overlay,按官方指使,获取Overlay的方法如下:

//首先为顶层视图创建一个key,通过key对象获取OverlayState
class MyApp extends StatelessWidget {
  //通过顶层视图的key,可以获取OverlayState对象
  static GlobalKey<NavigatorState> navigatorKey = new GlobalKey();
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Float Widget Demo',
      navigatorKey: navigatorKey,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: "首页",),
    );
  }
}

1.获取overlayState

MyApp.navigatorKey.currentState.overlay;

2.获取到overlayState对象,创建我们自己的视图,添加进去:

//展示悬浮组件
  showFloatWidget() {
    OverlayEntry overlayEntry = new OverlayEntry(builder: (context) {
      return Positioned(top: 100, left: 20, child: buildFloatWidget());
    });
    MyApp.navigatorKey.currentState.overlay.insert(overlayEntry);
    //保存这个引用,**用于清除这个组件**
    entryHolder = overlayEntry;
  }

至此我们已经自己添加了一个全局悬浮组件,拖动加两侧吸附实现比较简单,之后再更新。