新闻详情

新闻详情

首页 / 资讯中心 / 详情

歌词滚动效果实现详解

发布时间:2026/9/28 20:19:58来源:尧图网络
歌词滚动效果实现详解
歌词滚动效果实现详解1. 引入音乐播放器的歌词是怎么滚动的用过音乐播放器的都知道歌词会随着歌曲进度自动滚动当前唱的那一句高亮显示而且始终保持在屏幕中间。┌─────────────────────┐ │ 后来 我总算学会了 │ │ 如何去爱 │ │ ► 可惜你早已远去 ◄ │ ← 当前歌词高亮居中 │ 消失在人海 │ │ 后来 终于在眼泪中 │ └─────────────────────┘这个效果是怎么做的核心用到两个东西技术作用RecyclerView显示歌词列表LinearSmoothScroller让指定歌词平滑滚动到中间2. 整体思路1. 用RecyclerView显示所有歌词 2. 监听歌曲播放进度 3. 根据进度找到当前应该唱的那句歌词 4. 用LinearSmoothScroller把这句歌词滚到屏幕中间 5. 高亮显示当前歌词其他歌词正常显示3. 歌词数据解析3.1 歌词文件格式[00:00.00] 后来 [00:05.32] 我总算学会了 [00:10.15] 如何去爱 [00:15.42] 可惜你早已远去 [00:20.18] 消失在人海3.2 解析歌词publicclassLyric{privatelongtime;// 歌词开始时间毫秒privateStringcontent;// 歌词内容publicLyric(longtime,Stringcontent){this.timetime;this.contentcontent;}publiclonggetTime(){returntime;}publicStringgetContent(){returncontent;}}// 解析歌词publicListLyricparseLyric(StringlyricText){ListLyriclyricsnewArrayList();String[]lineslyricText.split(\n);for(Stringline:lines){// 匹配 [00:05.32]歌词内容PatternpatternPattern.compile(\\[(\\d{2}):(\\d{2})\\.(\\d{2})\\](.*));Matchermatcherpattern.matcher(line);if(matcher.find()){intminuteInteger.parseInt(matcher.group(1));intsecondInteger.parseInt(matcher.group(2));intmillisInteger.parseInt(matcher.group(3));Stringcontentmatcher.group(4).trim();longtimeminute*60*1000second*1000millis*10;lyrics.add(newLyric(time,content));}}returnlyrics;}4. RecyclerView显示歌词4.1 布局文件androidx.recyclerview.widget.RecyclerViewandroid:idid/rv_lyricandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:overScrollModeneverandroid:scrollbarsnone/4.2 歌词Item布局TextViewandroid:idid/tv_lyricandroid:layout_widthmatch_parentandroid:layout_height60dpandroid:gravitycenterandroid:textSize16spandroid:textColor#999999android:maxLines1android:ellipsizeend/4.3 AdapterpublicclassLyricAdapterextendsRecyclerView.AdapterLyricAdapter.LyricHolder{privateListLyriclyricList;privateintcurrentPosition-1;// 当前歌词位置publicLyricAdapter(ListLyriclyricList){this.lyricListlyricList;}// 更新当前歌词位置publicvoidsetCurrentPosition(intposition){intoldPositioncurrentPosition;currentPositionposition;// 刷新旧的和新的只刷新两个Item性能好if(oldPosition0){notifyItemChanged(oldPosition);}if(currentPosition0){notifyItemChanged(currentPosition);}}OverridepublicLyricHolderonCreateViewHolder(ViewGroupparent,intviewType){ViewviewLayoutInflater.from(parent.getContext()).inflate(R.layout.item_lyric,parent,false);returnnewLyricHolder(view);}OverridepublicvoidonBindViewHolder(LyricHolderholder,intposition){LyriclyriclyricList.get(position);holder.tvLyric.setText(lyric.getContent());// 当前歌词高亮if(positioncurrentPosition){holder.tvLyric.setTextColor(Color.WHITE);holder.tvLyric.setTextSize(18);}else{holder.tvLyric.setTextColor(Color.parseColor(#999999));holder.tvLyric.setTextSize(16);}}OverridepublicintgetItemCount(){returnlyricList.size();}staticclassLyricHolderextendsRecyclerView.ViewHolder{TextViewtvLyric;publicLyricHolder(ViewitemView){super(itemView);tvLyricitemView.findViewById(R.id.tv_lyric);}}}5. 核心让歌词滚到中间5.1 问题smoothScrollToPosition的局限// 这样滚动目标Item只会滚到屏幕边缘或可见位置recyclerView.smoothScrollToPosition(position);问题smoothScrollToPosition()只是让目标Item可见不保证在屏幕正中间。5.2 解决方案自定义LinearSmoothScroller重写LinearSmoothScroller让它把目标Item居中显示publicclassCenterSmoothScrollerextendsLinearSmoothScroller{publicCenterSmoothScroller(Contextcontext){super(context);}// 关键计算目标位置偏移量OverridepublicintcalculateDtToFit(intviewStart,intviewEnd,intboxStart,intboxEnd,intsnapPreference){// 返回当前View中心到父容器中心的距离return(boxStartboxEnd)/2-(viewStartviewEnd)/2;}}calculateDtToFit解释参数说明viewStart目标View的起始坐标viewEnd目标View的结束坐标boxStartRecyclerView的起始坐标boxEndRecyclerView的结束坐标snapPreference对齐偏好核心公式偏移量 (RecyclerView中心) - (目标View中心)这样滚动时目标Item就会居中对齐。5.3 使用自定义SmoothScroller// 创建LayoutManagerLinearLayoutManagerlayoutManagernewLinearLayoutManager(this){OverridepublicvoidsmoothScrollToPosition(RecyclerViewrecyclerView,RecyclerView.Statestate,intposition){// 使用自定义的SmoothScrollerCenterSmoothScrollerscrollernewCenterSmoothScroller(recyclerView.getContext());scroller.setTargetPosition(position);startSmoothScroll(scroller);}};recyclerView.setLayoutManager(layoutManager);5.4 滚动到指定位置// 滚动到当前歌词位置会居中显示recyclerView.smoothScrollToPosition(currentPosition);6. 完整实现流程6.1 Activity/Fragment中初始化publicclassLyricActivityextendsAppCompatActivity{privateRecyclerViewrvLyric;privateLyricAdapteradapter;privateListLyriclyricList;privateLinearLayoutManagerlayoutManager;privateintcurrentPosition0;OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_lyric);rvLyricfindViewById(R.id.rv_lyric);// 1. 解析歌词lyricListparseLyric(lyricText);// 2. 设置AdapteradapternewLyricAdapter(lyricList);rvLyric.setAdapter(adapter);// 3. 设置LayoutManager带居中滚动layoutManagernewLinearLayoutManager(this){OverridepublicvoidsmoothScrollToPosition(RecyclerViewrecyclerView,RecyclerView.Statestate,intposition){CenterSmoothScrollerscrollernewCenterSmoothScroller(recyclerView.getContext());scroller.setTargetPosition(position);startSmoothScroll(scroller);}};rvLyric.setLayoutManager(layoutManager);}}6.2 监听歌曲进度// 假设用MediaPlayer播放mediaPlayer.setOnCompletionListener(mp-{// 播放完成});// 用Handler定期检查播放进度privateHandlerhandlernewHandler();privateRunnableupdateLyricRunnablenewRunnable(){Overridepublicvoidrun(){if(mediaPlayer!nullmediaPlayer.isPlaying()){// 获取当前播放位置intcurrentTimemediaPlayer.getCurrentPosition();// 找到当前应该唱的那句歌词intnewPositionfindCurrentLyric(currentTime);if(newPosition!currentPosition){currentPositionnewPosition;// 更新歌词高亮adapter.setCurrentPosition(currentPosition);// 滚动到中间rvLyric.smoothScrollToPosition(currentPosition);}// 每200毫秒更新一次handler.postDelayed(this,200);}}};// 根据时间找到对应的歌词位置privateintfindCurrentLyric(longtime){for(intilyricList.size()-1;i0;i--){if(timelyricList.get(i).getTime()){returni;}}return0;}// 开始更新handler.post(updateLyricRunnable);// 停止更新// handler.removeCallbacks(updateLyricRunnable);7. 优化技巧7.1 避免频繁滚动// 只在歌词变化时才滚动if(newPosition!currentPosition){currentPositionnewPosition;adapter.setCurrentPosition(currentPosition);rvLyric.smoothScrollToPosition(currentPosition);}7.2 用户手动滑动时暂停自动滚动booleanisUserScrollingfalse;rvLyric.addOnScrollListener(newRecyclerView.OnScrollListener(){OverridepublicvoidonScrollStateChanged(RecyclerViewrecyclerView,intnewState){if(newStateRecyclerView.SCROLL_STATE_DRAGGING){// 用户正在拖动isUserScrollingtrue;}elseif(newStateRecyclerView.SCROLL_STATE_IDLE){// 停止拖动延迟几秒后恢复自动滚动newHandler().postDelayed(()-isUserScrollingfalse,3000);}}});// 更新歌词时判断if(!isUserScrollingnewPosition!currentPosition){rvLyric.smoothScrollToPosition(newPosition);}7.3 调整滚动速度publicclassCenterSmoothScrollerextendsLinearSmoothScroller{OverrideprotectedfloatcalculateSpeedPerPixel(DisplayMetricsdisplayMetrics){// 返回值越小滚动越快return50f/displayMetrics.densityDpi;}}展示8. 核心API总结API作用LinearSmoothScroller平滑滚动器calculateDtToFit()计算目标位置偏移量居中关键setTargetPosition()设置目标位置startSmoothScroll()开始平滑滚动calculateSpeedPerPixel()控制滚动速度9. 易错点总结易错点说明直接调用smoothScrollToPosition不会居中只会滚到可见位置忘记重写smoothScrollToPosition自定义Scroller不生效频繁调用smoothScrollToPosition导致卡顿应只在歌词变化时调用用户滑动时仍自动滚动体验差应暂停自动滚动高亮刷新用notifyDataSetChanged性能差应只刷新变化的两个Item10. 一句话总结歌词滚动的核心就是RecyclerView显示歌词 重写LinearSmoothScroller的calculateDtToFit方法让目标歌词居中 监听播放进度定时滚动。其中calculateDtToFit是关键它通过计算目标View中心与RecyclerView中心的偏移量实现居中滚动效果。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

《P14079 [GESP202509 八级] 最短距离》 2026/9/28 21:10:41

《P14079 [GESP202509 八级] 最短距离》

题目背景 对应的选择、判断题&#xff1a;试题 - GESP 202509 C 八级 - 洛谷有题 题目描述 给定正整数 p,q 以及常数 N1018。现在构建一张包含 N 个结点的带权无向图&#xff0c;结点依次以 1,2,…,N 编号。对于任意满足 1≤u<v≤N 的 u,v&#xff0c;向图中加入一条连接…

阅读更多 →
企业级AI Coding实战:如何让AI真正读懂你的系统? 2026/9/28 21:10:41

企业级AI Coding实战:如何让AI真正读懂你的系统?

存量系统里&#xff0c;瓶颈到底在哪 普通互联网项目用 AI 写代码很简单&#xff1a;需求进来&#xff0c;写个 Prompt&#xff0c;AI 分析、写代码、跑测试&#xff0c;基本就完事了。因为项目没什么历史包袱&#xff0c;技术栈公开&#xff0c;架构简单&#xff0c;规模也可…

阅读更多 →
2026年AI编程进阶路线:从Vibe Coding到企业级智能体架构实战 2026/9/28 21:10:41

2026年AI编程进阶路线:从Vibe Coding到企业级智能体架构实战

2026年AI编程进阶路线&#xff1a;从Vibe Coding到企业级智能体架构实战摘要&#xff1a;随着大模型技术爆发&#xff0c;AI编程范式正在发生剧变。从传统手写业务代码&#xff0c;到Vibe Coding指挥AI生成代码&#xff0c;再到自主开发AI智能体服务。很多开发者盲目内卷微调、…

阅读更多 →
AWS SDK for Python(Boto3)调用 Amazon Rekognition 完整实战指南 2026/9/28 21:10:41

AWS SDK for Python(Boto3)调用 Amazon Rekognition 完整实战指南

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地…

阅读更多 →
国产 AI Agent 框架怎么选,元气 Bot 与 ArkClaw 到底适合谁 2026/9/28 21:10:41

国产 AI Agent 框架怎么选,元气 Bot 与 ArkClaw 到底适合谁

选型困境&#xff1a;当 AI Agent 从概念走向落地在 AI 应用开发的浪潮中&#xff0c;开发者们正面临一个甜蜜的烦恼&#xff1a;国产 AI Agent 框架层出不穷&#xff0c;但哪一款才是你手中的“瑞士军刀”&#xff1f;社区里戏称的“四只龙虾”——元气 Bot、ArkClaw、DuClaw …

阅读更多 →
OpenMausBot语音模式:如何让AI Bot开口回话,甚至接打语音电话 2026/9/28 21:10:28

OpenMausBot语音模式:如何让AI Bot开口回话,甚至接打语音电话

OpenMausBot语音模式&#xff1a;如何让AI Bot开口回话&#xff0c;甚至接打语音电话 【免费下载链接】OpenMausBot Open Source Alternative to Grok Bot with a virtual machine that bots can use 项目地址: https://gitcode.com/gh_mirrors/op/OpenMausBot OpenMaus…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉