美文网首页
学习Flutter仿制网易云音乐APP

学习Flutter仿制网易云音乐APP

作者: qiufeng1ye | 来源:发表于2021-06-30 17:20 被阅读0次

    代码取自于不倦APP(简洁的三方网易播放器),作者sixbugs。


    我使用的是vscode环境,环境搭建可参考此文最后一段。环境搭建好后新建一个项目,打开pubspec.yaml文件设置要引用的包。

    dependencies:
      get: ^3.26.0
      path_provider: ^2.0.1
      color_thief_flutter: ^1.0.2
      cached_network_image: ^2.5.1
      flutter_placeholder_textlines: ^1.0.4
      starry:
        path: starry
      shared_preferences: ^2.0.4
      cookie_jar: ^2.0.0
      encrypt: ^3.0.0
      we_slide: ^2.1.0
      pull_to_refresh: ^1.6.5
      sleek_circular_slider: ^2.0.0
      dots_indicator: ^2.0.0
      progress_state_button: ^1.0.2
      direct_select_flutter: ^1.1.0
      on_audio_query: ^1.0.6
      flutter_screenutil: ^5.0.0
      dio: ^4.0.0
      url_launcher: ^6.0.3
      package_info: ^2.0.0
      flutter:
        sdk: flutter
    

    设置后点击右上角的“Get Packages”下载依赖,再打开lib下的main.dart文件。


    代码结构
    import 'api/answer.dart';
    import 'api/netease_cloud_music.dart';
    import 'global/global_binding.dart';
    import 'global/global_config.dart';
    import 'global/global_theme.dart';
    

    main.dart中引用的包主要是数据接口类和全局类。数据接口类调用的是网页云音乐开放的api,API文档地址参考为这里

    全局类

    使用DEBUG模式进入APP,将断点搭载runAPP一行,F11单点调试观察程序的运行情况。


    调试状态

    随着进入程序,可以发现首先在GlobalBinding中初始化了GlobalController、FindController、UserController三个实例。

    GlobalController
    GlobalController
    GlobalController主要用于初始化播放器。
    GlobalController下的addSliderListener方法如下,其用于监听点击底部播放栏状态的变化情况,使用了we_slide插件
      void addSliderListener(weSlideController,PreloadPageController pageController) {
        this.weSlideController = weSlideController;
        this.pageController = pageController;
        weSlideController.addListener(() {
          if (weSlideController.isOpened) {
            HomeController.to.resumeStream();
          } else {
            pageController?.jumpToPage(0);
            HomeController.to.pauseStream();
          }
        });
      }
    

    在音乐播放的部分使用了作者自己封装的StarrySky插件

      ///播放或暂停
      playOrPause() async {
        // if (playState.value == PlayState.ERROR || playState.value == PlayState.STOP)
        //   return;
        if (song.value.musicId == '-99') return;
        if (playState.value == PlayState.PLAYING) {
          await Starry.pauseMusic();
        } else {
          await Starry.restoreMusic();
        }
      }
    
      ///设置播放模式
      changePlayMode() {
        if (playListMode.value == PlayListMode.SONG) {
          //1->2->3
          var value = 1;
          switch (playMode.value) {
            case 1:
              value = 2;
              break;
            case 2:
              value = 3;
              break;
            case 3:
              value = 1;
              break;
          }
          Starry.setPlayMode(value);
        }
      }
    
    FindController
    FindController

    FindController主要用于初始化发现页。
    FindController下的loadTodaySheet方法如下,将获取的数据刷新至发现页上。

      loadTodaySheet({forcedRefresh = false}) {
        NetUtils()
            .getRecommendResource(forcedRefresh: forcedRefresh)
            .then((personalEntity) {
          if (personalEntity != null && personalEntity.code == 200) {
            var sheets = personalEntity.result;
            allSheet
              ..clear()
              ..addAll(sheets);
            sheet..clear();
            if (sheets.length == 6) {
              var i = sheets.length ~/ 3;
              for (int j = 0; j < i; j++) {
                sheet.add(sheets.sublist(j * 3, (j + 1) * 3));
              }
            }
          } else {
            loadState.value = LoadState.FAIL;
          }
        });
        loadNewSong();
      }
    
    UserController
    UserController

    UserController主要用于初始化用户页。

    页面类

    回到Main.Dart中继续跟踪程序的运行,进入runApp下的initialRoute,在app_outes.dart中对整个程序的路由绑定了对应的页面。

    class AppPages {
      static const INITIAL = '/home';
    
      static final routes = [
        GetPage(name: '/home', page: () => HomeView(), binding: HomeBinding()),
        GetPage(name: '/today', page: () => TodayView(), binding: TodayBinding()),
        GetPage(
            name: '/sheet',
            page: () => SheetInfoView(),
            binding: SheetInfoBinding()),
        GetPage(
            name: '/profile', page: () => ProfileView(), binding: ProfileBinding()),
        GetPage(
            name: '/setting', page: () => SettingView(), binding: SettingBinding()),
        GetPage(name: '/login', page: () => LoginView(), binding: LoginBinding()),
        GetPage(name: '/cloud', page: () => CloudView(), binding: CloudBinding()),
        GetPage(
            name: '/sheet_classify',
            page: () => SheetClassifyView(),
            binding: SheetClassifyBinding()),
        GetPage(
            name: '/music_talk',
            page: () => MusicTalkView(),
            binding: MusicTalkBinding()),
        GetPage(
            name: '/all_song',
            page: () => AllSongView(),
            binding: AllSongBinding()),
        GetPage(
            name: '/search_details',
            page: () => SearchDetailsView(),
            binding: SearchDetailBinding()),
        GetPage(name: '/local', page: () => MusicView(), binding: MusicBinding()),
        GetPage(name: '/top', page: () => TopView(), binding: TopBinding()),
        GetPage(
            name: '/local_album',
            page: () => LocalAlbumView(),
            binding: LocalAlbumBinding()),
        GetPage(
            name: '/donate', page: () => DonateView(), binding: DonateBinding()),
        GetPage(name: '/about', page: () => AboutView()),
        GetPage(name: '/album', page: () => AlbumView(), binding: AlbumBinding()),
        GetPage(
            name: '/history', page: () => HistoryView(), binding: HistoryBinding()),
        GetPage(name: '/radio', page: () => RadioView(), binding: RadioBinding()),
        GetPage(
            name: '/radio_detail',
            page: () => RadioDetailView(),
            binding: RadioDetailBinding()),
        GetPage(
            name: '/play_list_manager',
            page: () => PlayListManagerView(),
            binding: PlayListManagerBinding()),
      ];
    }
    

    本项目的路由管理用到了GetX包,GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。

    响应式数据
    controller定义初始数据源 ,需要继承 GetxController ;binding用于将控制器推入getx中,可以理解为要注册控制器;view中使用 GetView<T> 语法将 controller 和 binding 进行关联 ,内部可以直接使用 controller的实例调用数据和方法。
    使用 Obx(()=> widget) 语法,返回你要变更的组件, 让数据在视图上更新,并且是局部刷新的。 home_view的目录结构
    home_controller的目录结构

    以home页面为例,home_view主要由各类widget组成,home_controller里用于实现业务逻辑。

    相关文章

      网友评论

          本文标题:学习Flutter仿制网易云音乐APP

          本文链接:https://www.haomeiwen.com/subject/vsnnyltx.html