news 2026/8/29 8:44:44

Flutter for OpenHarmony音乐播放器App实战10:歌单列表实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony音乐播放器App实战10:歌单列表实现

歌单列表页面展示各种分类的歌单,用户可以通过分类筛选找到感兴趣的歌单。我们使用分类标签栏配合网格布局实现这个页面。本篇将详细介绍如何实现一个功能完善的歌单列表页面。

功能分析

歌单列表页面需要实现以下功能:分类标签栏(全部、流行、摇滚、民谣等)、歌单网格展示、点击歌单进入详情页、分类切换时更新歌单列表。这个页面是用户发现新歌单的重要入口,设计上需要让用户能快速找到感兴趣的分类。

核心技术点

本篇涉及的核心技术包括:横向滚动的分类标签栏、GridView网格布局、状态管理(选中的分类)、页面导航传参、数据驱动的UI构建方式。

对应代码文件

lib/pages/playlist/playlist_list_page.dart

完整代码实现

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

这段代码导入了Flutter核心库、GetX状态管理库以及歌单详情页面。GetX提供了简洁的路由导航API,方便我们进行页面跳转和参数传递。

classPlaylistListPageextendsStatefulWidget{constPlaylistListPage({super.key});@overrideState<PlaylistListPage>createState()=>_PlaylistListPageState();}

PlaylistListPage继承StatefulWidget,因为需要管理选中的分类状态。当用户点击不同分类时,页面需要更新显示对应分类的歌单列表。

class_PlaylistListPageStateextendsState<PlaylistListPage>{// 当前选中的分类String_selectedCategory='全部';// 分类列表finalList<String>_categories=['全部','流行','摇滚','民谣','电子','古典','爵士',];

_selectedCategory存储当前选中的分类,默认是"全部"。_categories是分类列表,包含了常见的音乐风格分类。实际项目中这个列表可能从服务器获取。

@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('歌单广场'),elevation:0,),body:Column(children:[// 分类标签栏_buildCategoryBar(),// 歌单网格Expanded(child:_buildPlaylistGrid(),),],),);}

build方法构建页面UI。Scaffold提供基础页面结构,AppBar显示"歌单广场"标题。页面使用Column垂直排列分类标签栏和歌单网格,Expanded让网格占据剩余空间。

/// 构建分类标签栏Widget_buildCategoryBar(){returnSizedBox(height:50,child:ListView.builder(scrollDirection:Axis.horizontal,padding:constEdgeInsets.symmetric(horizontal:16),itemCount:_categories.length,itemBuilder:(context,index){finalcategory=_categories[index];finalisSelected=category==_selectedCategory;return_buildCategoryItem(category,isSelected);},),);}

分类标签栏固定高度50像素,使用横向滚动的ListView.builder实现。scrollDirection设为Axis.horizontal让列表横向滚动,这样可以支持更多分类而不会占用太多垂直空间。

/// 构建单个分类标签Widget_buildCategoryItem(Stringcategory,bool isSelected){returnGestureDetector(onTap:(){setState((){_selectedCategory=category;});},child:Container(margin:constEdgeInsets.only(right:12),padding:constEdgeInsets.symmetric(horizontal:16),alignment:Alignment.center,decoration:BoxDecoration(color:isSelected?constColor(0xFFE91E63):constColor(0xFF1E1E1E),borderRadius:BorderRadius.circular(20),),child:Text(category,style:TextStyle(color:isSelected?Colors.white:Colors.grey,fontSize:14,fontWeight:isSelected?FontWeight.w500:FontWeight.normal,),),),);}

GestureDetector处理点击事件,点击时调用setState更新选中的分类。Container使用条件表达式设置背景色,选中状态为粉色主题色,未选中为深灰色。BorderRadius.circular(20)让标签呈胶囊形状。

/// 构建歌单网格Widget_buildPlaylistGrid(){returnGridView.builder(padding:constEdgeInsets.all(16),gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2,childAspectRatio:0.85,crossAxisSpacing:12,mainAxisSpacing:12,),itemCount:20,itemBuilder:(context,index){return_buildPlaylistItem(index);},);}

GridView.builder用于构建网格布局,采用懒加载方式只构建可见区域的子项。gridDelegate配置网格为2列,宽高比0.85,间距12像素。itemCount设为20表示显示20个歌单。

/// 构建单个歌单项Widget_buildPlaylistItem(int index){returnGestureDetector(onTap:(){Get.to(()=>PlaylistDetailPage(id:index));},child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[// 歌单封面Expanded(child:_buildPlaylistCover(index),),constSizedBox(height:8),// 歌单标题_buildPlaylistTitle(index),],),);}

GestureDetector处理点击事件,通过Get.to导航到歌单详情页并传递歌单ID。Column垂直排列封面和标题,crossAxisAlignment设为start让内容左对齐。

/// 构建歌单封面Widget_buildPlaylistCover(int index){returnContainer(decoration:BoxDecoration(borderRadius:BorderRadius.circular(12),color:Colors.primaries[index%Colors.primaries.length].withOpacity(0.3),boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.1),blurRadius:8,offset:constOffset(0,4),),],),child:Stack(children:[// 封面图标constCenter(child:Icon(Icons.queue_music,size:50,color:Colors.white70,),),// 播放量Positioned(right:8,top:8,child:Container(padding:constEdgeInsets.symmetric(horizontal:6,vertical:2,),decoration:BoxDecoration(color:Colors.black.withOpacity(0.5),borderRadius:BorderRadius.circular(10),),child:Row(mainAxisSize:MainAxisSize.min,children:[constIcon(Icons.play_arrow,color:Colors.white,size:12,),constSizedBox(width:2),Text('${(index+1)*10}万',style:constTextStyle(color:Colors.white,fontSize:10,),),],),),),],),);}

封面使用Container配合BoxDecoration实现圆角背景和阴影效果。Stack叠加封面图标和播放量标签,Positioned将播放量定位在右上角。播放量使用半透明黑色背景,让文字在任何颜色的封面上都清晰可见。

/// 构建歌单标题Widget_buildPlaylistTitle(int index){returnText('$_selectedCategory歌单${index+1}',style:constTextStyle(fontSize:14,fontWeight:FontWeight.w400,),maxLines:2,overflow:TextOverflow.ellipsis,);}}

歌单标题中包含当前选中的分类名称,切换分类时标题也会相应变化。maxLines限制最多显示两行,overflow设置溢出时显示省略号,保证界面整洁。

分类标签栏实现详解

分类标签使用横向滚动的ListView.builder实现,这是处理横向列表的标准方式:

// 横向滚动列表的关键配置ListView.builder(scrollDirection:Axis.horizontal,// 设置为横向滚动padding:constEdgeInsets.symmetric(horizontal:16),itemCount:_categories.length,itemBuilder:(context,index){// 构建每个标签},)

scrollDirection设为Axis.horizontal是关键配置,让列表从左到右滚动。padding设置水平内边距,让第一个和最后一个标签不会紧贴屏幕边缘。

GridView网格布局说明

GridView.builder是创建网格列表的最佳选择,它采用懒加载方式只构建可见区域的子项:

// 网格布局配置详解GridView.builder(padding:constEdgeInsets.all(16),gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2,// 每行显示2列childAspectRatio:0.85,// 子项宽高比crossAxisSpacing:12,// 列间距mainAxisSpacing:12,// 行间距),itemCount:20,itemBuilder:(context,index){returnbuildItem(index);},)

SliverGridDelegateWithFixedCrossAxisCount定义网格布局规则,crossAxisCount设置列数,childAspectRatio设置宽高比(宽度/高度),小于1表示高度大于宽度。

动态颜色分配

封面使用Colors.primaries数组中的颜色,通过取模运算让每个歌单有不同的颜色:

// 动态颜色分配color:Colors.primaries[index%Colors.primaries.length].withOpacity(0.3)

Colors.primaries是Flutter内置的主色调数组,包含红、粉、紫、蓝、青、绿、黄、橙等18种颜色。取模运算确保index超出数组长度时能循环使用颜色。

状态管理说明

页面使用StatefulWidget管理选中的分类状态:

// 状态更新onTap:(){setState((){_selectedCategory=category;});}

setState会触发build方法重新执行,UI会根据新的状态重新渲染。分类标签的颜色和歌单标题都会相应更新。

页面导航与传参

点击歌单时使用GetX进行页面导航:

// 页面导航Get.to(()=>PlaylistDetailPage(id:index))

Get.to是GetX提供的导航方法,比Navigator.push更简洁。通过构造函数传递歌单ID,详情页可以根据ID加载对应的歌单数据。

小结

本篇实现了音乐播放器的歌单列表页面。通过横向滚动的分类标签栏让用户快速筛选感兴趣的歌单类型,使用GridView网格布局展示歌单。setState管理选中状态,配合条件渲染实现UI的动态更新。封面上叠加播放量标签,让用户快速了解歌单的热度。这种设计模式在很多内容类App中都很常见。


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

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

Flutter for OpenHarmony音乐播放器App实战14:专辑详情实现

专辑详情页是展示专辑完整信息的页面&#xff0c;用户可以查看专辑封面、歌手信息、发行时间以及专辑内的所有歌曲。本篇文章将详细介绍如何使用CustomScrollView和Sliver组件实现一个美观实用的专辑详情页面。 页面基础结构 专辑详情页使用StatelessWidget&#xff0c;因为页…

作者头像 李华
网站建设 2026/8/21 21:21:17

Flutter for OpenHarmony音乐播放器App实战24:我喜欢的音乐实现

我喜欢的音乐是用户收藏歌曲的专属歌单&#xff0c;用户可以在这里找到所有标记为喜欢的歌曲。本篇将详细介绍如何实现我喜欢的音乐页面&#xff0c;包括歌单头部设计、排序功能和歌曲操作菜单。 功能分析 我喜欢的音乐页面需要实现以下功能&#xff1a;渐变封面展示、歌曲数…

作者头像 李华
网站建设 2026/8/22 2:57:47

遗传算法的静态二维栅格路径规划附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

作者头像 李华
网站建设 2026/8/24 6:32:34

计算机Net毕设实战-基于net的实验室管理信息系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

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

作者头像 李华