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

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

最后来张效果图

相关推荐
m0_748247801 天前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
迷雾漫步者1 天前
Flutter组件————PageView
flutter·跨平台·dart
迷雾漫步者1 天前
Flutter组件————FloatingActionButton
前端·flutter·dart
coder_pig2 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜2 天前
flutter自学笔记5- dart 编码规范
flutter·dart
恋猫de小郭2 天前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
sunly_3 天前
Flutter:导航,tab切换,顶部固定,列表分页滚动
开发语言·javascript·flutter
敲代码的小强3 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos
Zh-jie3 天前
flutter 快速实现侧边栏
前端·javascript·flutter
truemi.734 天前
flutter --no-color pub get 超时解决方法
android·flutter