核心内容摘要
极境之径:gogogo“全球大但”,开启你的硬核人生下半场
首页是用户进入App后看到的第一个内容页面它需要展示最重要的信息和功能入口。
音乐播放器的首页通常包含Banner轮播、快捷入口、推荐歌单、热门歌手、新碟上架等模块。
本篇我们来实现一个功能丰富的首页。
功能分析首页需要实现以下功能顶部搜索入口、Banner区域展示每日推荐、快捷入口、推荐歌单网格展示、热门歌手横向滚动列表、新碟上架横向滚动列表。
核心技术点本篇涉及的核心技术包括SingleChildScrollView实现页面滚动、GridView.builder实现网格布局、ListView.builder实现横向滚动列表、数据驱动的UI构建方式。
对应代码文件lib/pages/home/home_page.dart完整代码实现importpackage:flutter/material.dart;importpackage:get/get.dart;import../search/search_page.dart;import../playlist/playlist_detail_page.dart;import../artist/artist_detail_page.dart;import../album/album_detail_page.dart;import../ranking/ranking_page.dart;import../daily/daily_recommend_page.dart;classHomePageextendsStatelessWidget{constHomePage({super.key});overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText(音乐播放器),actions:[IconButton(icon:constIcon(Icons.search),onPressed:()Get.to(()constSearchPage()),),],),上面这段代码导入了必要的依赖和子页面。
HomePage使用StatelessWidget因为不需要管理内部状态。
AppBar右侧放置搜索按钮点击后使用GetX导航到搜索页面。
body:SingleChildScrollView(padding:constEdgeInsets.all(
,child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[_buildBanner(),constSizedBox(height:
,_buildQuickActions(),constSizedBox(height:
,_buildSection(推荐歌单,_buildPlaylistGrid()),constSizedBox(height:
,_buildSection(热门歌手,_buildArtistList()),constSizedBox(height:
,_buildSection(新碟上架,_buildAlbumList()),constSizedBox(height:
,],),),);}SingleChildScrollView包裹Column实现整体滚动。
padding设置16像素内边距crossAxisAlignment设为start让内容左对齐。
底部留100像素空间避免被迷你播放器遮挡。
Widget_buildBanner(){returnGestureDetector(onTap:()Get.to(()constDailyRecommendPage()),child:Container(height:160,decoration:BoxDecoration(borderRadius:BorderRadius.circular(
,gradient:constLinearGradient(begin:Alignment.topLeft,end:Alignment.bottomRight,colors:[Color(0xFFE91E
,Color(0xFF9C27B
],),boxShadow:[BoxShadow(color:constColor(0xFFE91E
.withOpacity(
0.
,blurRadius:15,offset:constOffset(0,
,),],),Banner是首页的视觉焦点高度160像素使用16像素圆角。
渐变从粉色到紫色与App主题一致boxShadow添加粉色阴影让Banner有悬浮效果。
点击跳转到每日推荐页面。
child:Stack(children:[Positioned(right:20,bottom:20,child:Icon(Icons.headphones,size:100,color:Colors.white.withOpacity(
0.
,),),Padding(padding:constEdgeInsets.all(
,child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Container(padding:constEdgeInsets.symmetric(horizontal:8,vertical:
,decoration:BoxDecoration(color:Colors.white.withOpacity(
0.
,borderRadius:BorderRadius.circular(
,),child:constText(每日推荐,style:TextStyle(color:Colors.white,fontSize:
,),),Stack叠加背景装饰图标和文字内容。
Positioned将耳机图标定位在右下角作为装饰使用20%透明度不抢夺视觉焦点。
标签使用半透明白色背景的胶囊形状。
constSizedBox(height:
,constText(发现你的专属音乐,style:TextStyle(color:Colors.white,fontSize:24,fontWeight:FontWeight.bold,),),constSizedBox(height:
,constText(根据你的口味每天为你推荐30首歌曲,style:TextStyle(color:Colors.white70,fontSize:
,),],),),],),),);}主标题使用24像素粗体白色大字副标题使用白色70%透明度形成主次层次。
SizedBox添加固定间距让布局整齐。
Widget_buildQuickActions(){finalactions[{icon:Icons.today,label:每日推荐,color:constColor(0xFFE91E
,onTap:()Get.to(()constDailyRecommendPage()),},{icon:Icons.leaderboard,label:排行榜,color:constColor(0xFF9C27B
,onTap:()Get.to(()constRankingPage()),},{icon:Icons.radio,label:私人FM,color:constColor(0xFF2196F
,onTap:(){},},{icon:Icons.album,label:新碟,color:constColor(0xFF4CAF
,onTap:(){},},];快捷入口使用数据驱动方式构建每个入口包含图标、文字、颜色和点击回调。
这种方式让代码更易维护添加或修改入口只需修改数据即可。
returnRow(mainAxisAlignment:MainAxisAlignment.spaceAround,children:actions.map((action){returnGestureDetector(onTap:action[onTap]asVoidCallback,child:Column(children:[Container(width:56,height:56,decoration:BoxDecoration(color:(action[color]asColor).withOpacity(
0.
,borderRadius:BorderRadius.circular(
,),child:Icon(action[icon]asIconData,color:action[color]asColor,size:28,),),constSizedBox(height:
,Text(action[label]asString,style:constTextStyle(fontSize:
,),],),);}).toList(),);}Row的spaceAround让入口均匀分布。
每个入口使用不同颜色增加视觉区分度图标背景使用10%透明度的对应颜色。
Widget_buildSection(Stringtitle,Widgetchild){returnColumn(crossAxisAlignment:CrossAxisAlignment.start,children:[Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:[Text(title,style:constTextStyle(fontSize:18,fontWeight:FontWeight.bold,),),GestureDetector(onTap:(){},child:constRow(children:[Text(更多,style:TextStyle(color:Colors.grey,fontSize:
,),Icon(Icons.chevron_right,color:Colors.grey,size:
,],),),],),constSizedBox(height:
,child,],);}通用Section组件封装标题行和内容区域避免重复代码。
标题行左侧显示标题右侧显示更多按钮让页面结构更清晰。
Widget_buildPlaylistGrid(){returnGridView.builder(shrinkWrap:true,physics:constNeverScrollableScrollPhysics(),gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3,childAspectRatio:
75,crossAxisSpacing:12,mainAxisSpacing:12,),itemCount:6,itemBuilder:(context,index){returnGestureDetector(onTap:()Get.to(()PlaylistDetailPage(id:index)),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Expanded(child:Container(decoration:BoxDecoration(borderRadius:BorderRadius.circular(
,color:Colors.primaries[index%Colors.primaries.length].withOpacity(
0.
,),GridView.builder的shrinkWrap让高度自适应内容NeverScrollableScrollPhysics禁用内部滚动。
gridDelegate配置3列、
75宽高比、12像素间距。
child:Stack(children:[constCenter(child:Icon(Icons.queue_music,size:40,color:Colors.white70,),),Positioned(top:4,right:4,child:Container(padding:constEdgeInsets.symmetric(horizontal:6,vertical:2,),decoration:BoxDecoration(color:Colors.black45,borderRadius:BorderRadius.circular(
,),child:Row(mainAxisSize:MainAxisSize.min,children:[constIcon(Icons.play_arrow,size:12,color:Colors.white,),Text(${(index
*10}万,style:constTextStyle(color:Colors.white,fontSize:10,),),],),),),],),),),constSizedBox(height:
,Text(推荐歌单${index1},style:constTextStyle(fontSize:
,maxLines:2,overflow:TextOverflow.ellipsis,),],),);},);}每个歌单项包含封面和标题封面右上角显示播放量。
Stack叠加音乐图标和播放量角标Positioned精确定位角标位置。
Widget_buildArtistList(){returnSizedBox(height:110,child:ListView.builder(scrollDirection:Axis.horizontal,itemCount:10,itemBuilder:(context,index){returnGestureDetector(onTap:()Get.to(()ArtistDetailPage(id:index)),child:Container(width:80,margin:constEdgeInsets.only(right:
,child:Column(children:[Container(width:64,height:64,decoration:BoxDecoration(shape:BoxShape.circle,color:Colors.primaries[index%Colors.primaries.length].withOpacity(
0.
,border:Border.all(color:constColor(0xFFE91E
.withOpacity(
0.
,width:2,),),child:constIcon(Icons.person,color:Colors.white70,size:32,),),SizedBox固定高度110像素scrollDirection设为Axis.horizontal实现横向滚动。
每个歌手项宽80像素圆形头像使用粉色边框与主题色呼应。
constSizedBox(height:
,Text(歌手${index1},style:constTextStyle(fontSize:
,maxLines:1,overflow:TextOverflow.ellipsis,textAlign:TextAlign.center,),Text(${(index
*50}首,style:constTextStyle(fontSize:10,color:Colors.grey,),),],),),);},),);}歌手名和歌曲数量显示在头像下方maxLines和overflow确保文字过长时显示省略号。
歌曲数量使用灰色小字作为辅助信息。
Widget_buildAlbumList(){returnSizedBox(height:180,child:ListView.builder(scrollDirection:Axis.horizontal,itemCount:10,itemBuilder:(context,index){returnGestureDetector(onTap:()Get.to(()AlbumDetailPage(id:index)),child:Container(width:130,margin:constEdgeInsets.only(right:
,child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Container(height:130,decoration:BoxDecoration(borderRadius:BorderRadius.circular(
,color:Colors.primaries[index%Colors.primaries.length].withOpacity(
0.
,boxShadow:[BoxShadow(color:Colors.black.withOpacity(
0.
,blurRadius:8,offset:constOffset(0,
,),],),新碟列表高度180像素每个专辑项宽130像素。
封面区域高130像素添加阴影增加立体感。
child:Stack(children:[constCenter(child:Icon(Icons.album,size:50,color:Colors.white70,),),Positioned(bottom:8,right:8,child:Container(width:32,height:32,decoration:constBoxDecoration(shape:BoxShape.circle,color:Color(0xFFE91E
,),child:constIcon(Icons.play_arrow,color:Colors.white,size:20,),),),],),),constSizedBox(height:
,Text(专辑${index1},style:constTextStyle(fontSize:
,maxLines:1,overflow:TextOverflow.ellipsis,),Text(歌手${index1},style:constTextStyle(fontSize:11,color:Colors.grey,),maxLines:1,overflow:TextOverflow.ellipsis,),],),),);},),);}}封面右下角有粉色圆形播放按钮是整个专辑项的视觉焦点。
下方显示专辑名和歌手名歌手名使用灰色小字作为辅助信息。
GridView与ListView对比GridView适合展示网格布局的内容如歌单封面、图片墙等。
ListView适合展示列表形式的内容设置scrollDirection为Axis.horizontal可实现横向滚动。
两者都支持builder模式实现懒加载只构建可见区域的项目提升性能。
数据驱动UI的优势使用List或Map存储数据通过map方法遍历生成Widget这种方式让代码更易维护。
添加、删除或修改内容只需修改数据源不需要改动UI构建逻辑。
这也是Flutter推荐的声明式UI编程方式。
小结本篇实现了音乐播放器的首页通过SingleChildScrollView实现页面滚动使用GridView和ListView分别展示网格和列表内容。
抽取通用的Section组件减少重复代码使用数据驱动的方式构建快捷入口。
首页包含Banner、快捷入口、推荐歌单、热门歌手、新碟上架等模块为用户提供丰富的内容入口。
欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net