SVG技术深度解析:从矢量原理到现代应用
2026/7/22 4:01:34
音乐播放器(Music Player)是一款模拟音乐播放应用,支持歌曲列表浏览、播放/暂停控制、上一曲/下一曲切换、进度调节、随机/循环播放模式、收藏管理、音量控制和播放列表管理。该应用以HarmonyOS NEXT的ArkTS框架为基础,深入展示了播放控制逻辑、状态管理、列表渲染、播放模式算法、收藏管理和用户交互设计等关键技术。
| 功能模块 | 功能描述 | 技术实现 | 设计考量 |
|---|---|---|---|
| 歌曲列表 | 浏览所有歌曲 | LazyForEach列表渲染 | 虚拟列表优化 |
| 播放控制 | 播放/暂停/上一曲/下一曲 | 状态机管理 | 无缝切换 |
| 进度条 | 歌曲进度显示与调节 | Slider组件 + 时间格式化 | 拖拽跳转 |
| 播放模式 | 顺序/随机/单曲循环 | 状态切换算法 | 3种模式 |
| 收藏功能 | 收藏喜欢的歌曲 | Set集合管理 | 持久化存储 |
| 音量控制 | 音量调节 | Slider组件 | 系统音量联动 |
| 播放列表 | 创建/编辑播放列表 | 列表管理 | 拖拽排序 |
| 歌曲搜索 | 按名称/歌手搜索 | 字符串匹配 | 实时过滤 |
音乐播放器应用采用分层架构:
enumPlaybackState{IDLE='idle',PLAYING='playing',PAUSED='paused',STOPPED='stopped'}enumPlaybackMode{SEQUENTIAL='sequential',// 顺序播放SHUFFLE='shuffle',// 随机播放REPEAT_ONE='repeat_one'// 单曲循环}interfaceSong{id:string;title:string;artist:string;album:string;duration:number;// 时长(秒)coverColor:string;// 封面颜色genre:string;year:number;isFavorite:boolean;}interfacePlaylist{id:string;name:string;description:string;songs:string[];// 歌曲ID列表createdAt:number;updatedAt:number;}classMusicPlayerEngine{@StateplaybackState:PlaybackState=PlaybackState.IDLE;@StatecurrentSongIndex:number=0;@StatecurrentTime:number=0;// 当前播放进度(秒)@Stateduration:number=0;// 当前歌曲时长(秒)@Statevolume:number=80;// 音量 0-100@StateplaybackMode:PlaybackMode=PlaybackMode.SEQUENTIAL;@StateisFavorite:boolean=false;privateplaylist:Song[]=[];privateshuffleHistory:number[]=[];// 随机播放历史privatetimerId:number|null=null;// 播放指定歌曲playSong(index:number):void{if(index<0||index>=this.playlist.length)return;this.currentSongIndex=index;this.currentTime=0;this.duration=this.playlist[index].duration;this.playbackState=PlaybackState.PLAYING;this.isFavorite=this.playlist[index].isFavorite;this.startProgressTimer();}// 播放/暂停切换togglePlayPause():void{if(this.playbackState===PlaybackState.PLAYING){this.pause();}else{this.resume();}}privatepause():void{this.playbackState=PlaybackState.PAUSED;this.stopProgressTimer();}privateresume():void{if(this.playbackState===PlaybackState.PAUSED){this.playbackState=PlaybackState.PLAYING;this.startProgressTimer();}elseif(this.playbackState===PlaybackState.IDLE&&this.playlist.length>0){this.playSong(0);}}// 下一曲nextSong():void{constnextIndex=this.getNextIndex();this.playSong(nextIndex);}// 上一曲previousSong():void{// 如果当前进度超过3秒,重新播放当前歌曲if(this.currentTime>3){this.currentTime=0;return;}constprevIndex=this.getPreviousIndex();this.playSong(prevIndex);}// 根据播放模式获取下一首索引privategetNextIndex():number{switch(this.playbackMode){casePlaybackMode.SEQUENTIAL:return(this.currentSongIndex+1)%this.playlist.length;casePlaybackMode.SHUFFLE:returnthis.getShuffleNextIndex();casePlaybackMode.REPEAT_ONE:returnthis.currentSongIndex;// 重复当前default:return(this.currentSongIndex+1)%this.playlist.length;}}privategetPreviousIndex():number{return(this.currentSongIndex-1+this.playlist.length)%this.playlist.length;}privategetShuffleNextIndex():number{// 随机播放但不重复已播放的歌曲constavailable=this.playlist.map((_,i)=>i).filter(i=>!this.shuffleHistory.includes(i)&&i!==this.currentSongIndex);if(available.length===0){this.shuffleHistory=[this.currentSongIndex];returnthis.getShuffleNextIndex();}constrandomIndex=available[Math.floor(Math.random()*available.length)];this.shuffleHistory.push(randomIndex);returnrandomIndex;}// 进度更新privatestartProgressTimer():void{this.stopProgressTimer();this.timerId=setInterval(()=>{this.currentTime++;if(this.currentTime>=this.duration){if(this.playbackMode===PlaybackMode.REPEAT_ONE){this.currentTime=0;}else{this.nextSong();}}},1000);}privatestopProgressTimer():void{if(this.timerId!==null){clearInterval(this.timerId);this.timerId=null;}}// 跳转到指定进度seekTo(time:number):void{this.currentTime=Math.max(0,Math.min(time,this.duration));}// 格式化时间formatTime(seconds:number):string{constmins=Math.floor(seconds/60);constsecs=Math.floor(seconds%60);return`${mins}:${secs.toString().padStart(2,'0')}`;}}classFavoriteManager{privatefavorites:Set<string>=newSet();privateprefs:preferences.Preferences|null=null;asyncinit(context:Context):Promise<void>{this.prefs=awaitpreferences.getPreferences(context,'music_prefs');awaitthis.load();}toggleFavorite(songId:string):boolean{if(this.favorites.has(songId)){this.favorites.delete(songId);this.save();returnfalse;}else{this.favorites.add(songId);this.save();returntrue;}}isFavorite(songId:string):boolean{returnthis.favorites.has(songId);}getFavoriteSongs(songs:Song[]):Song[]{returnsongs.filter(s=>this.favorites.has(s.id));}getFavoriteCount():number{returnthis.favorites.size;}privateasyncload():Promise<void>{if(!this.prefs)return;constjson=awaitthis.prefs.get('favorites','[]');try{this.favorites=newSet(JSON.parse(json));}catch{this.favorites=newSet();}}privateasyncsave():Promise<void>{if(!this.prefs)return;awaitthis.prefs.put('favorites',JSON.stringify(Array.from(this.favorites)));awaitthis.prefs.flush();}}@Componentstruct PlayerControlBar{@LinkplaybackState:PlaybackState;@LinkcurrentTime:number;@Linkduration:number;@LinkplaybackMode:PlaybackMode;@Linkvolume:number;@LinkcurrentSong:Song|null;onPlayPause:(()=>void)|null=null;onNext:(()=>void)|null=null;onPrevious:(()=>void)|null=null;onSeek:((time:number)=>void)|null=null;onModeChange:(()=>void)|null=null;build(){Column(){// 进度条Slider({value:this.currentTime,min:0,max:this.duration,step:1}).width('100%').onChange((value:number)=>{this.onSeek?.(value);})Row(){Text(this.formatTime(this.currentTime)).fontSize(12).fontColor('#666666')Text(this.formatTime(this.duration)).fontSize(12).fontColor('#666666')}.width('100%').justifyContent(FlexAlign.SpaceBetween)// 控制按钮Row(){Button(this.getModeIcon()).fontSize(20).backgroundColor('transparent').onClick(()=>{this.onModeChange?.();})Button('⏮').fontSize(24).backgroundColor('transparent').onClick(()=>{this.onPrevious?.();})Button(this.playbackState===PlaybackState.PLAYING?'⏸':'▶️').fontSize(32).width(56).height(56).backgroundColor('#4CAF50').borderRadius(28).onClick(()=>{this.onPlayPause?.();})Button('⏭').fontSize(24).backgroundColor('transparent').onClick(()=>{this.onNext?.();})}.width('100%').justifyContent(FlexAlign.SpaceEvenly).padding(8)}.padding(16).backgroundColor('#FFFFFF').borderRadius(16).shadow({radius:8,color:'#20000000',offsetY:-4})}privategetModeIcon():string{switch(this.playbackMode){casePlaybackMode.SEQUENTIAL:return'🔁';casePlaybackMode.SHUFFLE:return'🔀';casePlaybackMode.REPEAT_ONE:return'🔂';}}privateformatTime(seconds:number):string{constm=Math.floor(seconds/60);consts=Math.floor(seconds%60);return`${m}:${s.toString().padStart(2,'0')}`;}}| 模块 | 核心代码行数 | 接口数 | 组件数 |
|---|---|---|---|
| 播放引擎 | 180 | 10 | - |
| 收藏管理器 | 70 | 5 | - |
| 播放列表管理器 | 100 | 6 | - |
| UI组件 | 280 | 5 | 5 |
| 总计 | 630 | 26 | 5 |