在这里插入图片描述

我的音乐库是用户管理个人音乐的中心,包含本地音乐、下载管理、最近播放、收藏歌曲等功能入口,以及用户创建的歌单列表。这个页面是用户个人音乐资产的集中展示,需要清晰地组织各种功能入口。本篇我们来实现这个功能丰富的音乐库页面。

功能分析

我的音乐库页面需要实现以下功能:音乐统计卡片(本地歌曲数、收藏数、歌单数)、快捷入口列表(本地音乐、下载管理、最近播放、我的收藏)、创建的歌单列表、创建新歌单入口。这个页面是用户管理个人音乐的核心入口,设计上需要层次分明、操作便捷。

核心技术点

本篇涉及的核心技术包括:渐变卡片展示统计数据、ListTile构建快捷入口列表、ListView.builder展示歌单列表、数据驱动的UI构建方式、GetX路由导航。

对应代码文件

lib/pages/music/my_music_page.dart

完整代码实现

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../local/local_music_page.dart';
import '../download/download_page.dart';
import '../recent/recent_play_page.dart';
import '../favorite/favorite_page.dart';
import '../playlist/create_playlist_page.dart';

这段代码导入了Flutter核心库、GetX状态管理库以及各个功能页面。我的音乐库需要跳转到本地音乐、下载管理、最近播放、收藏和创建歌单等页面,因此需要导入这些页面的引用。GetX提供了简洁的路由导航API。

class MyMusicPage extends StatelessWidget {
  const MyMusicPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我的音乐')
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            _buildMusicStats(),
            const SizedBox(height: 24),

MyMusicPage继承StatelessWidget,因为页面不需要管理内部状态。Scaffold提供基础页面结构,AppBar显示"我的音乐"标题。SingleChildScrollView包裹Column实现整体滚动,padding设置16像素的内边距让内容与边缘保持距离。

            _buildQuickAccess(),
            const SizedBox(height: 24),
            _buildMyPlaylists(),
            const SizedBox(height: 100),
          ],
        ),
      ),
    );
  }

页面主体包含三个模块:音乐统计卡片、快捷入口列表和我的歌单。每个模块之间使用SizedBox添加24像素间距,底部留100像素空间避免被迷你播放器遮挡。这种模块化的布局方式让代码结构清晰,便于维护和扩展。

  Widget _buildMusicStats() {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        gradient: const LinearGradient(
          colors: [
            Color(0xFFE91E63),
            Color(0xFF9C27B0)
          ]
        ),
        borderRadius: BorderRadius.circular(16)
      ),

_buildMusicStats方法构建音乐统计卡片。Container使用渐变背景,从粉色(E91E63)过渡到紫色(9C27B0),配合16像素圆角。这种渐变设计让卡片更有视觉吸引力,同时与App的主题色保持一致。

      child: const Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Column(
            children: [
              Text(
                '128',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                  fontWeight: FontWeight.bold
                )
              ),
              Text(
                '本地歌曲',
                style: TextStyle(color: Colors.white70)
              )
            ]
          ),

Row水平排列三组统计数据,spaceAround让它们均匀分布在卡片中。每组统计数据使用Column垂直排列数字和标签。数字使用24像素白色粗体字突出显示,标签使用白色70%透明度作为辅助信息,形成主次分明的视觉层次。

          Column(
            children: [
              Text(
                '56',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                  fontWeight: FontWeight.bold
                )
              ),
              Text(
                '收藏歌曲',
                style: TextStyle(color: Colors.white70)
              )
            ]
          ),
          Column(
            children: [
              Text(
                '12',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                  fontWeight: FontWeight.bold
                )
              ),
              Text(
                '创建歌单',
                style: TextStyle(color: Colors.white70)
              )
            ]
          ),
        ],
      ),
    );
  }

三组数据分别展示本地歌曲、收藏歌曲和创建歌单的数量,让用户快速了解自己的音乐资产概况。统一的样式设计保证了视觉一致性,渐变背景让整个卡片成为页面的视觉焦点。

  Widget _buildQuickAccess() {
    final items = [
      {
        'icon': Icons.folder,
        'label': '本地音乐',
        'count': '128',
        'page': () => const LocalMusicPage()
      },
      {
        'icon': Icons.download,
        'label': '下载管理',
        'count': '45',
        'page': () => const DownloadPage()
      },
      {
        'icon': Icons.history,
        'label': '最近播放',
        'count': '200',
        'page': () => const RecentPlayPage()
      },
      {
        'icon': Icons.favorite,
        'label': '我的收藏',
        'count': '56',
        'page': () => const FavoritePage()
      },
    ];

_buildQuickAccess方法构建快捷入口列表。items列表存储每个入口的数据,包括图标、文字标签、数量和对应的页面构造函数。使用Map结构存储数据,方便后续遍历和访问。这种数据驱动的方式让代码更易维护,添加或修改入口只需修改数据即可。

    return Column(
      children: items.map((item) => ListTile(
        leading: Container(
          width: 44,
          height: 44,
          decoration: BoxDecoration(
            color: const Color(0xFFE91E63).withOpacity(0.1),
            borderRadius: BorderRadius.circular(12)
          ),
          child: Icon(
            item['icon'] as IconData,
            color: const Color(0xFFE91E63)
          )
        ),

使用map方法遍历items生成ListTile列表。leading放置图标容器,使用粉色10%透明度背景和12像素圆角。图标使用粉色主题色,与整体设计风格保持一致。Container的固定尺寸确保所有图标容器大小一致。

        title: Text(item['label'] as String),
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              item['count'] as String,
              style: const TextStyle(color: Colors.grey)
            ),
            const Icon(
              Icons.chevron_right,
              color: Colors.grey
            )
          ]
        ),
        onTap: () => Get.to(item['page'] as Widget Function()),
      )).toList(),
    );
  }

title显示入口名称,trailing显示数量和箭头图标。mainAxisSize设为min让Row只占必要宽度,避免撑满整行。onTap通过Get.to导航到对应页面,实现页面跳转功能。toList()将map结果转换为List供Column使用。

  Widget _buildMyPlaylists() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const Text(
              '创建的歌单',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold
              )
            ),
            IconButton(
              icon: const Icon(
                Icons.add_circle_outline,
                color: Color(0xFFE91E63)
              ),
              onPressed: () => Get.to(
                () => const CreatePlaylistPage()
              )
            ),
          ],
        ),

_buildMyPlaylists方法构建歌单列表模块。标题行左侧显示"创建的歌单",右侧放置添加按钮,点击跳转到创建歌单页面。添加按钮使用粉色主题色,突出显示可操作性。spaceBetween让标题和按钮分别靠左和靠右。

        ListView.builder(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemCount: 5,
          itemBuilder: (context, index) => ListTile(
            leading: Container(
              width: 50,
              height: 50,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8),
                color: Colors.primaries[index % Colors.primaries.length]
                    .withOpacity(0.3)
              ),
              child: const Icon(
                Icons.queue_music,
                color: Colors.white70
              )
            ),

ListView.builder构建歌单列表,shrinkWrap设为true让列表高度自适应内容,NeverScrollableScrollPhysics禁用内部滚动避免与外层滚动冲突。leading放置歌单封面,使用不同颜色的半透明背景区分不同歌单,增加视觉多样性。

            title: Text('我的歌单 ${index + 1}'),
            subtitle: Text('${(index + 1) * 10} 首'),
            trailing: const Icon(Icons.more_vert),
          ),
        ),
      ],
    );
  }
}

title显示歌单名称,subtitle显示歌曲数量,trailing放置更多操作按钮。每个歌单项包含封面、名称、数量和操作按钮,信息展示完整且布局紧凑。点击更多按钮可以弹出操作菜单。

渐变卡片设计详解

渐变卡片使用LinearGradient实现颜色过渡效果,从粉色(E91E63)过渡到紫色(9C27B0)。这种设计让统计卡片更有视觉吸引力,同时与App的主题色保持一致。配合圆角和内边距,整体效果更加精致。渐变方向默认从左到右,也可以通过begin和end参数自定义。

数据驱动的列表构建

快捷入口列表使用数据驱动的方式构建,将图标、文字、数量和页面信息存储在Map中,通过map方法遍历生成ListTile。这种方式让代码更易维护,添加或修改入口只需修改数据即可,无需改动UI代码。这是Flutter开发中常用的模式。

ListView嵌套滚动处理

在SingleChildScrollView中嵌套ListView时,需要设置shrinkWrap为true让ListView高度自适应,同时设置NeverScrollableScrollPhysics禁用内部滚动,避免滚动冲突。这是Flutter中常见的嵌套滚动处理方式,确保用户体验流畅。

GetX路由导航说明

GetX提供了简洁的路由导航API,Get.to()方法接收页面构造函数作为参数,自动处理页面跳转动画和返回逻辑。相比Navigator.push,代码更加简洁,且不需要context参数,可以在任何地方调用。

小结

本篇实现了音乐播放器的我的音乐库页面。通过渐变卡片展示音乐统计数据,使用ListTile构建快捷入口列表,用ListView展示用户创建的歌单。数据驱动的方式让代码更易维护,统一的样式设计保证了视觉一致性。音乐库页面为用户提供了管理个人音乐的完整功能入口,是音乐App的重要组成部分。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐