Flutter仿网易云音乐(三)全局音乐播放栏

前言

网易云音乐ios端和android端底部的音乐栏几乎都覆盖了所有页面,但是还是有些许不同:

从上图可以看出ios端的音乐栏在页面切换时总是固定的,而android端则有一个较为明显的路由切换动画。

在编程开始之前,先来了解一下在Android原生中是如何实现的,知乎文章:www.zhihu.com/question/36...

从最高赞回答中可以知晓,在Android原生中实现固定音乐栏的方法,就是在每个activity都写一个音乐栏...

呃...这种方法不说繁琐,简直就是麻烦。没有批评网易大佬的意思,也许他们有更多的考量。

那么如果在flutter实现固定音乐栏的话,有没有更简单的方法呢。

悬浮窗

的确,如果创建一个固定位置的悬浮窗的话,实现出来的效果应该会和ios端更贴近,即页面跳转时无路由动画。

那么应该怎么实现悬浮窗呢?

最简单的方法就是OverlayEntry了。

一、封装一个OverlayEntry

音乐栏全局有且只有一个,因此使用工厂模式创建单例类:

scss 复制代码
class MusicBar {
  static final MusicBar _instance = MusicBar._();
  factory MusicBar() => _instance;
  MusicBar._();
  
  ///显示音乐栏
  OverlayEntry? overlayEntry;
  show(BuildContext context,Widget child,{double? top,double? left}) {
    if (overlayEntry == null) {
      overlayEntry = OverlayEntry(builder: (BuildContext context) {
        return MusicBarWidget(
          top: top??100,
          left: left??100,
          child: child,
        );
      });
      Overlay.of(context)?.insert(overlayEntry!);
    }
  }
  ///隐藏音乐栏
  void hide() {
    overlayEntry?.remove();
    overlayEntry = null;
  }
}

二、封装悬浮窗Widget

网易云音乐首页音乐栏下面还有个导航栏,当路由至其他界面时导航栏消失,这时音乐栏的下方就会空出一片地方。参考ios的处理方法,我添加了一段下沉动画,而回到首页时再上浮回来,同样用eventbus广播。

ini 复制代码
​
class _MusicBarWidgetState extends State<MusicBarWidget>
    with TickerProviderStateMixin {
  AnimationController? _controller;
  double left = 0;
  double top = 0;
  double maxX = 0;
  double maxY = 0;
  var parentKey = GlobalKey();
  var childKey = GlobalKey();
  var parentSize = const Size(0, 0);
  var childSize = const Size(0, 0);
  late StreamSubscription _subscription;
​
  @override
  void initState() {
    _subscription = eventBus.on().listen((event) {
      EventObj eventObj = event;
      if (eventObj.code == EventCode.toBottom) {
        toBottom();
      }
      if (eventObj.code == EventCode.riseUp) {
        riseUp();
      }
    });
    left = widget.left;
    top = widget.top;
    WidgetsBinding.instance.addPostFrameCallback((d) {
      parentSize = getWidgetSize(parentKey);
      childSize = getWidgetSize(childKey);
      maxX = parentSize.width - childSize.width;
      maxY = parentSize.height - childSize.height;
    });
    super.initState();
  }
​
  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }
​
  @override
  Widget build(BuildContext context) {
    return Stack(
      key: parentKey,
      fit: StackFit.expand,
      children: [
        Positioned(
          key: childKey,
          left: left,
          top: top,
          child: widget.child,
        )
      ],
    );
  }
​
  //底部导航栏消失时沉底
  void toBottom() {
    _controller = AnimationController(vsync: this)..duration = widget.duration;
    var animation = Tween<double>(begin: top, end: maxY).animate(_controller!);
    animation.addListener(() {
      top = animation.value;
      setState(() {});
    });
    _controller!.forward();
  }
​
  //底部导航栏出现时抬高
  void riseUp() {
    _controller = AnimationController(vsync: this)..duration = widget.duration;
    var animation =
        Tween<double>(begin: top, end: maxY - 56).animate(_controller!);
    animation.addListener(() {
      top = animation.value;
      setState(() {});
    });
    _controller!.forward();
  }
​
  Size getWidgetSize(GlobalKey key) {
    final RenderBox renderBox =
        key.currentContext?.findRenderObject() as RenderBox;
    return renderBox.size;
  }
}
​

三、使用方法

scss 复制代码
MusicBar smallWindowManager = MusicBar();
smallWindowManager.show(
    context,
    _musicBar(size,smallWindowManager,context),top: size.height-ScreenUtil().setWidth(70)-56,left: 0);
//_musicBar()为Widget,样式自己编写

虽然这样子实现的悬浮窗不受路由影响,但是在某些页面需要隐藏的情况下也需要注意显示隐藏的逻辑,在特定的生命周期进行显示隐藏。

最后来张效果图

相关推荐
江上清风山间明月21 小时前
Flutter开发的应用页面非常多时如何高效管理路由
android·flutter·路由·页面管理·routes·ongenerateroute
Zsnoin能1 天前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人1 天前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen1 天前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang2 天前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang2 天前
Flutter项目中设置安卓启动页
android·flutter
JIngles1232 天前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-2 天前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11192 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
机器瓦力2 天前
Flutter应用开发:对象存储管理图片
flutter