news 2026/3/10 16:42:04

Flutter for OpenHarmony音乐播放器App实战17:每日推荐实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony音乐播放器App实战17:每日推荐实现

每日推荐是音乐播放器中一个非常受欢迎的功能,系统根据用户的听歌习惯每天推荐一批歌曲。本篇将详细介绍如何实现每日推荐页面,包括日期展示、渐变头部设计和推荐歌曲列表。

功能分析

每日推荐页面需要实现以下功能:渐变头部显示当前日期、播放全部按钮、收藏和下载按钮、推荐歌曲列表。这个页面是用户发现新歌的重要入口,设计上需要突出日期信息和推荐歌曲。

核心技术点

本篇涉及的核心技术包括:CustomScrollView和Sliver组件、SliverAppBar可折叠头部、LinearGradient渐变背景、SliverList歌曲列表、DateTime日期处理。

对应代码文件

lib/pages/daily/daily_recommend_page.dart

完整代码实现

import'package:flutter/material.dart';classDailyRecommendPageextendsStatelessWidget{constDailyRecommendPage({super.key});@overrideWidgetbuild(BuildContextcontext){// 获取当前日期finalnow=DateTime.now();returnScaffold(body:CustomScrollView(slivers:[// 可折叠头部_buildSliverAppBar(now),// 操作栏_buildActionBar(),// 推荐歌曲列表_buildSongList(),],),);}

这段代码导入了Flutter核心库。DailyRecommendPage继承StatelessWidget,因为页面不需要管理内部状态。build方法中使用DateTime.now()获取当前日期。CustomScrollView是实现复杂滚动效果的核心组件。

/// 构建可折叠头部Widget_buildSliverAppBar(DateTimenow){returnSliverAppBar(expandedHeight:220,pinned:true,flexibleSpace:FlexibleSpaceBar(background:_buildHeaderBackground(now),),);}

SliverAppBar设置展开高度220像素,pinned为true表示折叠后固定在顶部。FlexibleSpaceBar定义可折叠区域的内容,当用户向上滚动时,头部会逐渐折叠。

/// 构建头部背景Widget_buildHeaderBackground(DateTimenow){returnContainer(decoration:constBoxDecoration(gradient:LinearGradient(begin:Alignment.topLeft,end:Alignment.bottomRight,colors:[Color(0xFFE91E63),Color(0xFF9C27B0),],),),child:SafeArea(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:[constSizedBox(height:40),// 日期数字_buildDateNumber(now),// 月份_buildMonthText(now),constSizedBox(height:8),// 说明文字_buildDescriptionText(),],),),);}

Container使用LinearGradient渐变背景,从粉色(E91E63)过渡到紫色(9C27B0),斜向渐变让视觉效果更加动感。SafeArea确保内容不被系统状态栏遮挡。Column垂直排列日期信息。

/// 构建日期数字Widget_buildDateNumber(DateTimenow){returnText('${now.day}',style:constTextStyle(color:Colors.white,fontSize:60,fontWeight:FontWeight.bold,shadows:[Shadow(color:Colors.black26,offset:Offset(2,2),blurRadius:4,),],),);}

日期数字使用60像素超大白色粗体字突出显示,这是每日推荐页面的标志性视觉元素。添加阴影效果让文字更有立体感,在渐变背景上更加清晰。

/// 构建月份文字Widget_buildMonthText(DateTimenow){returnText('${now.month}月',style:constTextStyle(color:Colors.white70,fontSize:18,),);}/// 构建说明文字Widget_buildDescriptionText(){returnconstText('根据你的音乐口味生成',style:TextStyle(color:Colors.white54,fontSize:14,),);}

月份使用18像素白色70%透明度作为辅助信息,说明文字使用白色54%透明度,作为最次要的信息。这种透明度层次让信息主次分明,用户一眼就能看出这是每日推荐功能。

/// 构建操作栏Widget_buildActionBar(){returnSliverToBoxAdapter(child:Padding(padding:constEdgeInsets.all(16),child:Row(children:[// 播放全部按钮Expanded(child:_buildPlayAllButton(),),constSizedBox(width:12),// 收藏按钮_buildIconButton(Icons.favorite_border),// 下载按钮_buildIconButton(Icons.download),],),),);}

SliverToBoxAdapter将普通Widget转换为Sliver,这是在CustomScrollView中使用普通组件的方式。操作栏使用Row水平排列按钮,Expanded让播放全部按钮占据主要位置。

/// 构建播放全部按钮Widget_buildPlayAllButton(){returnElevatedButton.icon(onPressed:(){// 播放全部歌曲},icon:constIcon(Icons.play_arrow),label:constText('播放全部'),style:ElevatedButton.styleFrom(backgroundColor:constColor(0xFFE91E63),foregroundColor:Colors.white,padding:constEdgeInsets.symmetric(vertical:12),shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(25),),),);}

播放全部使用ElevatedButton.icon,背景色使用粉色主题色。padding设置垂直内边距让按钮更高,shape设置圆角让按钮呈胶囊形状。这是最常用的操作,所以占据最大空间。

/// 构建图标按钮Widget_buildIconButton(IconDataicon){returnContainer(decoration:BoxDecoration(shape:BoxShape.circle,border:Border.all(color:Colors.grey.withOpacity(0.3),),),child:IconButton(icon:Icon(icon),onPressed:(){},color:Colors.grey,),);}

收藏和下载使用带边框的圆形IconButton,视觉上与播放全部按钮形成对比。Container添加圆形边框装饰,让按钮更加精致。

/// 构建推荐歌曲列表Widget_buildSongList(){returnSliverList(delegate:SliverChildBuilderDelegate((context,index)=>_buildSongItem(index),childCount:30,),);}

SliverList构建推荐歌曲列表,SliverChildBuilderDelegate实现懒加载,只构建可见区域的子项。childCount设为30,表示每日推荐包含30首歌曲。

/// 构建单个歌曲项Widget_buildSongItem(int index){returnListTile(leading:_buildSongCover(index),title:Text('每日推荐${index+1}',style:constTextStyle(fontSize:16,fontWeight:FontWeight.w400,),),subtitle:constText('歌手名称',style:TextStyle(color:Colors.grey,fontSize:13,),),trailing:_buildPlayButton(),onTap:(){// 播放歌曲},);}

ListTile是Flutter提供的列表项组件,leading放置歌曲封面,title显示歌曲名称,subtitle显示歌手名。trailing放置播放按钮,onTap处理点击事件。

/// 构建歌曲封面Widget_buildSongCover(int index){returnContainer(width:50,height:50,decoration:BoxDecoration(borderRadius:BorderRadius.circular(8),color:Colors.primaries[index%Colors.primaries.length].withOpacity(0.3),boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.1),blurRadius:4,offset:constOffset(0,2),),],),child:constIcon(Icons.music_note,color:Colors.white70,),);}

封面使用50x50像素的圆角容器,背景色从primaries颜色列表循环取值。添加阴影效果增加层次感,中央显示音乐图标作为占位。

/// 构建播放按钮Widget_buildPlayButton(){returnconstIcon(Icons.play_circle_outline,color:Color(0xFFE91E63),size:32,);}}

播放按钮使用粉色主题色突出显示,size设为32像素让按钮更容易点击。play_circle_outline图标是播放按钮的标准样式。

CustomScrollView和Sliver组件详解

CustomScrollView是Flutter中实现复杂滚动效果的核心组件,它的children必须是Sliver类型的组件:

// CustomScrollView基本结构CustomScrollView(slivers:[SliverAppBar(...),// 可折叠头部SliverToBoxAdapter(...),// 普通Widget转SliverSliverList(...),// 列表SliverGrid(...),// 网格],)

常用的Sliver组件包括SliverAppBar、SliverList、SliverGrid、SliverToBoxAdapter等。这种组合可以实现头部可折叠、列表滚动等复杂效果。

SliverAppBar可折叠头部

SliverAppBar是一个可以随滚动折叠的AppBar,提供了丰富的配置选项:

// SliverAppBar配置详解SliverAppBar(expandedHeight:220,// 展开时的高度pinned:true,// 折叠后是否固定在顶部floating:false,// 向下滚动时是否立即显示snap:false,// 是否有吸附效果flexibleSpace:FlexibleSpaceBar(background:// 背景内容),)

expandedHeight设置展开时的高度,pinned为true表示折叠后固定在顶部。FlexibleSpaceBar定义可折叠区域的内容。

LinearGradient渐变背景

LinearGradient用于创建线性渐变效果,是实现炫酷背景的常用方式:

// 渐变背景配置decoration:constBoxDecoration(gradient:LinearGradient(begin:Alignment.topLeft,// 渐变起点end:Alignment.bottomRight,// 渐变终点colors:[Color(0xFFE91E63),// 起始颜色(粉色)Color(0xFF9C27B0),// 结束颜色(紫色)],),)

begin和end定义渐变方向,从左上到右下的斜向渐变让视觉效果更加动感。colors数组定义渐变颜色。

SliverList列表实现

SliverList用于在CustomScrollView中创建列表,配合SliverChildBuilderDelegate实现懒加载:

// SliverList基本用法SliverList(delegate:SliverChildBuilderDelegate((context,index){returnListTile(...);},childCount:30,),)

SliverChildBuilderDelegate只构建可见区域的子项,对于长列表性能更好。childCount指定列表项总数。

DateTime日期处理

Flutter使用DateTime类处理日期和时间:

// 获取当前日期finalnow=DateTime.now();// 获取日期各部分int year=now.year;// 年int month=now.month;// 月int day=now.day;// 日

DateTime.now()获取当前日期时间,通过属性可以获取年、月、日等各部分。在每日推荐页面中,我们使用day和month来显示当前日期。

SliverToBoxAdapter说明

SliverToBoxAdapter用于将普通Widget转换为Sliver,这样就可以在CustomScrollView中使用:

// 将普通Widget转换为SliverSliverToBoxAdapter(child:Padding(padding:constEdgeInsets.all(16),child:Row(...),),)

这是在CustomScrollView中使用非Sliver组件的标准方式,比如操作栏、分割线等。

小结

本篇实现了音乐播放器的每日推荐页面。使用CustomScrollView和Sliver组件实现头部可折叠效果,渐变背景和大字号日期突出每日推荐的特点。SliverList实现歌曲列表的高效渲染,ListTile简化列表项构建。这种设计在各大音乐App中都很常见,掌握这些技术可以实现各种复杂的滚动界面效果。


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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/10 1:29:21

计算机深度学习毕设实战-基于人工智能python-CNN深度学习的蝴蝶识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/10 4:31:11

深度学习毕设项目推荐-基于python-CNN深度学习的蝴蝶识别

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/6 4:28:58

大模型分布式训练通信优化:从Ring All-Reduce到分层压缩的实战演进

摘要:本文深度揭秘大模型分布式训练中的通信瓶颈与优化体系。通过Ring All-Reduce的拓扑感知改进、梯度压缩算法(PowerSGDEF21)的融合实现、以及通信-计算重叠的流水线设计,在千卡集群上训练175B模型时,通信耗时占比从…

作者头像 李华
网站建设 2026/3/4 13:43:42

一文搞懂 C++ 仿函数与适配器:从概念到实战代码

如果你在学 C STL,可能会对 “仿函数”“适配器” 这两个词感到陌生 —— 明明有函数指针,为啥要搞仿函数?栈和队列看着像独立容器,怎么又和 “适配器” 挂钩了?其实这两个概念的核心特别简单:仿函数是 “像…

作者头像 李华
网站建设 2026/3/6 22:51:10

2024年9月GESP真题及题解(C++七级): 矩阵移动

2024年9月GESP真题及题解(C七级): 矩阵移动 题目描述 小杨有一个 nmn \times mnm 的矩阵,仅包含 01? 三种字符。矩阵的行从上到下编号依次为 1,2,…,n1,2,\dots, n1,2,…,n,列从左到右编号依次为 1,2,…,m1, 2, \dots, m1,2,…,m。小杨开始在矩阵的左上…

作者头像 李华