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,样式自己编写

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

最后来张效果图

相关推荐
带带弟弟学爬虫__1 小时前
Flutter 逆向想学却无从下手?
flutter
行者961 小时前
Flutter跨平台开发:颜色选择器适配OpenHarmony
flutter·harmonyos·鸿蒙
不爱吃糖的程序媛1 小时前
深度解析OpenHarmony跨平台框架生态:RN、Flutter、Cordova、KMP四大方向全梳理
flutter
kirk_wang2 小时前
Flutter艺术探索-Flutter样式系统:TextStyle与主题配置
flutter·移动开发·flutter教程·移动开发教程
火柴就是我2 小时前
Flutter 混合模式下:saveLayer 混合注意点
android·flutter
AiFlutter2 小时前
四、动画图表(03):饼图
flutter·低代码·低代码平台·aiflutter·aiflutter低代码
西西学代码2 小时前
Flutter---通过案例来详细了解状态管理
flutter
LawrenceLan3 小时前
Flutter 零基础入门(八):Dart 类(Class)与对象(Object)
前端·flutter
前端不太难3 小时前
Flutter 列表性能的一套“长期安全写法”
安全·flutter·状态模式
行者963 小时前
Flutter鸿蒙跨平台开发:实现高性能可拖拽排序列表组件
flutter·harmonyos·鸿蒙