在这里插入图片描述

我喜欢的音乐是用户收藏歌曲的专属歌单,用户可以在这里找到所有标记为喜欢的歌曲。本篇将详细介绍如何实现我喜欢的音乐页面,包括歌单头部设计、排序功能和歌曲操作菜单。

功能分析

我喜欢的音乐页面需要实现以下功能:渐变封面展示、歌曲数量统计、排序方式选择、歌曲列表展示、喜欢状态切换、歌曲操作菜单。这个页面是用户管理收藏歌曲的核心入口。

核心技术点

本篇涉及的核心技术包括:StatelessWidget页面构建、LinearGradient渐变背景、ListView.builder列表构建、showModalBottomSheet底部弹窗、GetX路由导航。

对应代码文件

lib/pages/favorite/favorite_page.dart

完整代码实现

import 'package:flutter/material.dart';
import 'package:get/get.dart';

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('我喜欢的音乐'),

这段代码导入了Flutter核心库和GetX状态管理库。FavoritePage继承StatelessWidget,因为页面状态相对简单。Scaffold提供基础页面结构,AppBar显示"我喜欢的音乐"标题。

        actions: [
          IconButton(
            icon: const Icon(Icons.sort),
            onPressed: () => _showSortOptions(context),
          ),
          IconButton(
            icon: const Icon(Icons.play_circle_filled),
            onPressed: () {},
          ),
        ],
      ),
      body: Column(
        children: [
          _buildHeader(),
          Expanded(child: _buildSongList()),
        ],
      ),
    );
  }

actions数组添加两个操作按钮:排序按钮和播放全部按钮。排序按钮点击后显示排序选项菜单,播放按钮可以直接播放全部喜欢的歌曲。body使用Column垂直排列头部和列表,Expanded让列表占据剩余空间。

  Widget _buildHeader() {
    return Container(
      padding: const EdgeInsets.all(16),
      child: Row(
        children: [
          Container(
            width: 120,
            height: 120,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(12),
              gradient: const LinearGradient(
                colors: [Color(0xFFE91E63), Color(0xFFFF5722)],
              ),
            ),
            child: const Icon(
              Icons.favorite,
              size: 60,
              color: Colors.white
            ),
          ),

_buildHeader方法构建歌单头部。封面使用120x120像素的圆角容器,LinearGradient创建从粉色到橙色的渐变背景。中央显示白色爱心图标,突出"我喜欢"的主题。这种渐变设计让封面更加温暖有活力。

          const SizedBox(width: 16),
          const Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '我喜欢的音乐',
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold
                  ),
                ),
                SizedBox(height: 8),
                Text(
                  '共 128 首',
                  style: TextStyle(color: Colors.grey),
                ),
                SizedBox(height: 8),
                Text(
                  '最近更新: 今天',
                  style: TextStyle(color: Colors.grey, fontSize: 12),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

封面右侧使用Column垂直排列歌单信息。crossAxisAlignment设为start让文字左对齐。显示歌单名称、歌曲总数和最近更新时间,让用户快速了解歌单的基本情况。Expanded让信息区域占据剩余宽度。

  Widget _buildSongList() {
    final songs = List.generate(20, (i) => {
      'title': '喜欢的歌曲 ${i + 1}',
      'artist': '歌手 ${i % 5 + 1}',
      'album': '专辑 ${i % 3 + 1}',
    });

    return ListView.builder(
      itemCount: songs.length,
      itemBuilder: (context, index) {
        final song = songs[index];
        return ListTile(
          leading: Container(
            width: 50,
            height: 50,

_buildSongList方法构建歌曲列表。List.generate生成20首模拟歌曲数据,实际项目中应从数据库或API获取。ListView.builder采用懒加载方式构建列表,只渲染可见区域的列表项,性能更好。

            decoration: BoxDecoration(
              color: Colors.primaries[index % Colors.primaries.length]
                  .withOpacity(0.3),
              borderRadius: BorderRadius.circular(8),
            ),
            child: const Icon(
              Icons.music_note,
              color: Colors.white
            ),
          ),
          title: Text(
            song['title']!,
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
          ),
          subtitle: Text(
            '${song['artist']} - ${song['album']}',
            style: const TextStyle(color: Colors.grey, fontSize: 12),
          ),

leading放置歌曲封面,使用50x50像素的圆角容器。背景色从primaries颜色列表循环取值,让每首歌有不同的颜色。title显示歌曲名称,maxLines限制一行,overflow设置溢出显示省略号。subtitle显示歌手和专辑信息。

          trailing: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              IconButton(
                icon: const Icon(
                  Icons.favorite,
                  color: Color(0xFFE91E63),
                  size: 20,
                ),
                onPressed: () {},
              ),
              IconButton(
                icon: const Icon(Icons.more_vert, size: 20),
                onPressed: () => _showSongOptions(context),
              ),
            ],
          ),
          onTap: () {},
        );
      },
    );
  }

trailing放置操作按钮区域。Row使用mainAxisSize.min让宽度自适应内容。喜欢按钮显示粉色实心爱心,表示已喜欢状态。更多按钮点击后显示操作菜单。onTap处理列表项点击,可以跳转到播放器页面。

  void _showSortOptions(BuildContext context) {
    showModalBottomSheet(
      context: context,
      backgroundColor: const Color(0xFF1E1E1E),
      builder: (context) => Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Padding(
            padding: EdgeInsets.all(16),
            child: Text(
              '排序方式',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold
              ),
            ),
          ),

_showSortOptions方法显示排序选项菜单。showModalBottomSheet创建底部弹窗,backgroundColor设置深色背景。Column使用mainAxisSize.min让高度自适应内容。顶部显示"排序方式"标题。

          ListTile(
            leading: const Icon(Icons.access_time),
            title: const Text('按添加时间'),
            onTap: () => Get.back(),
          ),
          ListTile(
            leading: const Icon(Icons.sort_by_alpha),
            title: const Text('按歌曲名'),
            onTap: () => Get.back(),
          ),
          ListTile(
            leading: const Icon(Icons.person),
            title: const Text('按歌手'),
            onTap: () => Get.back(),
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }

提供三种排序方式:按添加时间、按歌曲名、按歌手。每个选项使用ListTile构建,leading显示图标,title显示文字。点击后调用Get.back()关闭弹窗。实际项目中需要在点击后执行排序逻辑并刷新列表。

  void _showSongOptions(BuildContext context) {
    showModalBottomSheet(
      context: context,
      backgroundColor: const Color(0xFF1E1E1E),
      builder: (context) => Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          ListTile(
            leading: const Icon(Icons.playlist_add),
            title: const Text('添加到歌单'),
            onTap: () => Get.back(),
          ),
          ListTile(
            leading: const Icon(Icons.download),
            title: const Text('下载'),
            onTap: () => Get.back(),
          ),

_showSongOptions方法显示歌曲操作菜单。菜单包含添加到歌单、下载、分享和取消喜欢四个选项。每个选项使用ListTile构建,点击后关闭弹窗并执行对应操作。

          ListTile(
            leading: const Icon(Icons.share),
            title: const Text('分享'),
            onTap: () => Get.back(),
          ),
          ListTile(
            leading: const Icon(Icons.delete, color: Colors.red),
            title: const Text(
              '取消喜欢',
              style: TextStyle(color: Colors.red)
            ),
            onTap: () => Get.back(),
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }
}

取消喜欢选项使用红色图标和文字,提醒用户这是移除操作。点击后应该弹出确认对话框,避免用户误操作。SizedBox在底部添加间距,让菜单看起来更舒适。

渐变封面设计

封面使用LinearGradient创建渐变背景,从粉色(E91E63)过渡到橙色(FF5722)。这种暖色调渐变配合爱心图标,很好地表达了"喜欢"的主题。borderRadius.circular(12)让封面呈圆角矩形,视觉效果更加柔和。

ListView.builder列表构建

ListView.builder是构建长列表的最佳选择,它采用懒加载方式只构建可见区域的列表项。itemCount指定列表项总数,itemBuilder构建每个列表项。这种方式比直接使用ListView.children性能更好,特别是当列表项很多时。

ListTile列表项组件

ListTile是Flutter提供的标准列表项组件,包含leading、title、subtitle、trailing四个区域。leading通常放置图标或头像,title显示主要文字,subtitle显示辅助信息,trailing放置操作按钮。使用ListTile可以快速构建规范的列表界面。

showModalBottomSheet底部弹窗

showModalBottomSheet用于显示底部弹出菜单,是移动端常见的交互方式。backgroundColor设置弹窗背景色,builder构建弹窗内容。弹窗会自动处理手势关闭,也可以通过Get.back()或Navigator.pop()手动关闭。

小结

本篇实现了音乐播放器的我喜欢的音乐页面。通过渐变封面和爱心图标突出"喜欢"的主题,ListView.builder高效构建歌曲列表,底部弹窗提供排序和歌曲操作功能。这种设计模式在音乐App中非常常见,用户可以方便地管理自己收藏的歌曲。

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

Logo

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

更多推荐