当前位置: 首页 > news >正文

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

歌手列表页面展示所有歌手,用户可以浏览并点击进入歌手详情页。本篇我们使用网格布局来实现这个页面,每个歌手显示圆形头像和名称。这是音乐App中常见的歌手展示方式。

功能分析

歌手列表页面需要实现以下功能:网格布局展示歌手、圆形头像显示、点击歌手进入详情页、歌手分类筛选。这个页面是用户发现新歌手的重要入口,设计上需要让用户能快速浏览和找到感兴趣的歌手。

核心技术点

本篇涉及的核心技术包括:GridView.builder网格布局、CircleAvatar圆形头像、GestureDetector点击事件、GetX路由导航、动态颜色分配、分类筛选功能。

对应代码文件

lib/pages/artist/artist_list_page.dart

完整代码实现

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

这段代码导入了Flutter核心库、GetX状态管理库以及歌手详情页面。歌手列表需要跳转到歌手详情页,因此需要导入详情页的引用。

classArtistListPageextendsStatefulWidget{constArtistListPage({super.key});@overrideState<ArtistListPage>createState()=>_ArtistListPageState();}

ArtistListPage继承StatefulWidget,因为我们需要管理歌手分类的选中状态。当用户切换分类时,页面需要更新显示对应分类的歌手。

class_ArtistListPageStateextendsState<ArtistListPage>{// 当前选中的分类String_selectedType='全部';// 歌手类型列表finalList<String>_artistTypes=['全部','华语男','华语女','欧美男','欧美女','组合','乐队',];

_selectedType存储当前选中的歌手类型,默认是"全部"。_artistTypes是歌手类型列表,包含了常见的歌手分类方式,方便用户快速筛选。

@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('歌手'),elevation:0,),body:Column(children:[// 分类筛选栏_buildFilterBar(),// 歌手网格Expanded(child:_buildArtistGrid(),),],),);}

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

/// 构建分类筛选栏Widget_buildFilterBar(){returnSizedBox(height:50,child:ListView.builder(scrollDirection:Axis.horizontal,padding:constEdgeInsets.symmetric(horizontal:16),itemCount:_artistTypes.length,itemBuilder:(context,index){finaltype=_artistTypes[index];finalisSelected=type==_selectedType;return_buildFilterItem(type,isSelected);},),);}

分类筛选栏固定高度50像素,使用横向滚动的ListView.builder实现。这样可以支持更多分类选项而不会占用太多垂直空间,用户可以左右滑动查看所有分类。

/// 构建单个筛选项Widget_buildFilterItem(Stringtype,bool isSelected){returnGestureDetector(onTap:(){setState((){_selectedType=type;});},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(type,style:TextStyle(color:isSelected?Colors.white:Colors.grey,fontSize:14,),),),);}

GestureDetector处理点击事件,点击时调用setState更新选中的分类。Container使用条件表达式设置背景色,选中状态为粉色主题色,未选中为深灰色。圆角设为20像素呈胶囊形状。

/// 构建歌手网格Widget_buildArtistGrid(){returnGridView.builder(padding:constEdgeInsets.all(16),gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3,childAspectRatio:0.8,crossAxisSpacing:16,mainAxisSpacing:16,),itemCount:30,itemBuilder:(context,index){return_buildArtistItem(index);},);}

GridView.builder用于构建网格布局,采用懒加载方式只构建可见区域的子项。gridDelegate配置网格为3列,宽高比0.8,间距16像素。每行显示3个歌手,布局紧凑又不拥挤。

/// 构建单个歌手项Widget_buildArtistItem(int index){returnGestureDetector(onTap:(){Get.to(()=>ArtistDetailPage(id:index));},child:Column(children:[// 歌手头像Expanded(child:_buildArtistAvatar(index),),constSizedBox(height:8),// 歌手名称_buildArtistName(index),],),);}

GestureDetector处理点击事件,通过Get.to导航到歌手详情页并传递歌手ID。Column垂直排列头像和名称,Expanded让头像区域占据剩余空间。

/// 构建歌手头像Widget_buildArtistAvatar(int index){returnContainer(decoration:BoxDecoration(shape:BoxShape.circle,boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.2),blurRadius:8,offset:constOffset(0,4),),],),child:CircleAvatar(radius:45,backgroundColor:Colors.primaries[index%Colors.primaries.length].withOpacity(0.3),child:constIcon(Icons.person,size:40,color:Colors.white70,),),);}

头像使用Container包裹CircleAvatar,添加阴影效果增加层次感。CircleAvatar显示圆形头像,半径45像素。背景色从primaries颜色列表循环取值,让每个歌手有不同的颜色。

/// 构建歌手名称Widget_buildArtistName(int index){returnColumn(children:[Text('歌手${index+1}',style:constTextStyle(fontSize:14,fontWeight:FontWeight.w500,),maxLines:1,overflow:TextOverflow.ellipsis,),constSizedBox(height:2),Text('${(index+1)*5}首歌曲',style:constTextStyle(fontSize:11,color:Colors.grey,),),],);}}

歌手名称使用14像素字体,fontWeight设为w500稍微加粗。下方显示歌曲数量作为辅助信息,使用灰色小字体。maxLines限制只显示一行,overflow设置溢出时显示省略号。

GridView网格布局详解

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

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

padding设置网格的内边距,让内容不会紧贴屏幕边缘。crossAxisCount设为3表示每行显示3个歌手,这个数量在手机屏幕上显示效果较好。

SliverGridDelegateWithFixedCrossAxisCount说明

这个委托类用于定义网格的布局规则:

// 布局参数说明constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3,// 每行显示的列数childAspectRatio:0.8,// 子项的宽高比(宽/高)crossAxisSpacing:16,// 列间距mainAxisSpacing:16,// 行间距)

childAspectRatio设置子项的宽高比,0.8表示高度比宽度大一点,适合显示圆形头像加文字。crossAxisSpacing和mainAxisSpacing分别设置列间距和行间距。

CircleAvatar圆形头像组件

CircleAvatar是Flutter提供的圆形头像组件,非常适合显示用户头像:

// CircleAvatar基本用法CircleAvatar(radius:45,// 头像半径backgroundColor:Colors.blue,// 背景色backgroundImage:NetworkImage(url),// 网络图片child:Icon(Icons.person),// 子组件(无图片时显示))

radius设置头像半径,backgroundColor设置背景色。实际项目中可以使用backgroundImage加载网络图片,child作为图片加载失败时的占位显示。

动态颜色分配

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

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

Colors.primaries是Flutter内置的主色调数组,包含18种颜色。取模运算确保index超出数组长度时能循环使用颜色。withOpacity(0.3)降低透明度让颜色更柔和。

阴影效果实现

为头像添加阴影效果增加层次感:

// 阴影效果Container(decoration:BoxDecoration(shape:BoxShape.circle,boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.2),blurRadius:8,offset:constOffset(0,4),),],),child:CircleAvatar(...),)

BoxShadow的color设置阴影颜色,blurRadius设置模糊半径,offset设置阴影偏移。向下偏移4像素让阴影看起来像是光从上方照射。

文本溢出处理

歌手名称可能很长,需要处理溢出情况:

// 文本溢出处理Text('歌手名称',style:constTextStyle(fontSize:14),maxLines:1,overflow:TextOverflow.ellipsis,)

maxLines设为1限制只显示一行,overflow设为TextOverflow.ellipsis在文本溢出时显示省略号。这是处理长文本的常用方式,保证界面整洁。

页面导航实现

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

// 页面导航GestureDetector(onTap:()=>Get.to(()=>ArtistDetailPage(id:index)),child:// 歌手项内容)

Get.to是GetX提供的导航方法,通过构造函数传递歌手ID。详情页可以根据ID加载对应的歌手数据,包括歌手信息、热门歌曲、专辑列表等。

小结

本篇实现了音乐播放器的歌手列表页面。使用GridView.builder实现网格布局,每行显示3个歌手。CircleAvatar用于显示圆形头像,GestureDetector处理点击事件。分类筛选栏让用户可以快速找到感兴趣的歌手类型。这种网格布局在很多App中都会用到,比如通讯录、相册等。通过调整crossAxisCount和childAspectRatio参数,可以轻松适配不同的设计需求。


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

http://www.jsqmd.com/news/339327/

相关文章:

  • 开发智能体配置-隐私协议服务
  • 【计算机毕业设计案例】基于net的西安文化旅游信息管理系统的设计与实现(程序+文档+讲解+定制)
  • 如何通过API接口获取Target平台的目标详情数据
  • 香港科技大学团队发现形式化验证如何让AI推理更聪明
  • 【计算机毕业设计案例】基于net的实验室管理信息系统的设计与实现(程序+文档+讲解+定制)
  • 中国人民大学的研究突破:让AI思考过程更快更省的神奇方法
  • 对比分析:CSGHub vs. Hugging Face:模型管理平台选型对
  • 一文读懂银行、上金所、基金公司最新政策全影响
  • Spring MVC 慎用@InitBinder,谨防内存泄漏
  • 开机即用:现场画面、低空无人机图像指挥中心一目了然
  • SQL 中的 WITH ... AS ...
  • 数据不再混乱!JSON Crack 可视化 + cpolar,随时随地搞定复杂数据协作
  • mycat报错:63529
  • Python正则表达式终极指南:从模式匹配到文本工程的智能跃迁
  • 基于金枪鱼群优化算法图像重构附Matlab代码
  • DeepSeek-OCR 2:视觉因果流模型官方论文解读总结
  • 金仓赋能:关系数据库替换高效落地,Oracle 平滑迁移
  • 适配FOUP载具的晶圆搬运机械手,哪些型号维护更便捷?
  • 教师狂喜❗️魔果云课直接拉满教学效率[特殊字符]
  • 跨团队协作怎么做:一套可落地的研发项目管理框架与工具
  • 【程序员必学】GPT模型架构解析:预训练与微调技术详解(建议收藏)
  • 重塑机器人轻量化设计:PEEK精密注塑结构件壳体_高强度耐磨损
  • KingBase 备份操作手册
  • 收藏级|大模型学习不踩坑!小白程序员必看的“3阶9步”极简入门框架
  • 《升鲜宝供应链管理系统 功能详情说明(完整版)》
  • 从架构设计到实战策略:如何让公有云多可用区部署“永不宕机”?
  • 收藏必备!大模型智能体8大核心概念全解析,程序员入门必看指南
  • 加入大厂,却落入了边缘业务:这是职业选择的必然代价吗?
  • 从入门到年薪百万:AI大模型学习路线与技能图谱(必收藏)
  • 【强烈推荐】大模型Agent实战指南:能“自己想、自己干、自己复盘“的才是好Agent,5大主流框架对比与应用