新闻详情

新闻详情

首页 / 资讯中心 / 详情

歌词滚动效果实现详解

发布时间:2026/11/15 8:11:17来源:尧图网络
歌词滚动效果实现详解
歌词滚动效果实现详解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

相关资讯

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

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/15 4:54:16

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/15 2:04:12

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/14 10:11:15

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/14 17:14:38

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/14 16:35:50

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/15 4:06:36

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

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

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