先上图:

我只是做了个假的效果,真正做的时候需要根据当前歌曲的进度判断歌词扫描的进度;
原理是:1. 自定义一个歌词的view,用来控制每行歌词的扫描进度
2.自定义一个viewGroup,控制歌词的上下滚动
3.通过延时消息控制1和2的交替运行
4.每次滚动,都判断最上面一行有没有到顶部,到顶部则隐藏之
activity的布局就是一个fFrameLayout包裹一个2中定义的自定义ViewGroup,就不贴出来了; activity代码如下:

public class LrcActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_lrc);findViews();initData();//首先第一句歌词需要展示在中间scrollToCenter();//开始滚动歌词startScroll();}private void startScroll() {    Message message = Message.obtain();message.what = ACTION_SWIPE;handler.sendMessage(message);}private void scrollToCenter() {krcListView.post(new Runnable() {@Overridepublic void run() {krcListView.scrollToCenter();}});}private void initData() {KrcView krcView = null;for(int i=0;i<30;i++){krcView = new KrcView(strList[i],this);krcListView.addView(krcView);}}private void findViews() {krcListView = (KrcListView) findViewById(R.id.krcListView);}private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case ACTION_SWIPE:post(swipeRunnable);break;case ACTION_SCROLL:post(scrollRunnable);break;case ACTION_REMOVE_TOP:krcListView.setTopInvisible(index);break;case ACTION_SCROLL_CENTER:krcListView.scrollToCenter();break;}}};private Runnable scrollRunnable = new Runnable() {@Overridepublic void run() {index++;//遍历每行歌词的画笔颜色krcListView.setChildPaint(index);if(index >= krcListView.getChildCount()){//滚动到最后一行时,恢复到第一行的初始状态Message message = Message.obtain();message.what = ACTION_SCROLL_CENTER;handler.sendMessage(message);}else{if(index >= KrcListView.MAX_SIZE / 2 - 1){//隐藏最上面一行Message message1 = Message.obtain();message1.what = ACTION_REMOVE_TOP;handler.sendMessageDelayed(message1, 500);}//滚动一行krcListView.scrollSingleHeight();}//发送扫描的消息Message message = Message.obtain();message.what = ACTION_SWIPE;handler.sendMessage(message);}};private Runnable swipeRunnable = new Runnable() {@Overridepublic void run() {index = index >= krcListView.getChildCount() ? 0 : index;//找到当前选中的那行,并以每次百分之5的进度扫描KrcView krcView = (KrcView)krcListView.getChildAt(index);krcView.swipeProgress(swipeProgress);krcView.invalidate();Message message = Message.obtain();if(swipeProgress >= 1.0f){//如果该行扫描结束,则开始滚动swipeProgress = 0.0f;message.what = ACTION_SCROLL;handler.sendMessage(message);}else{//如果该行没有扫描结束,则进度加0.05,继续扫描swipeProgress += 0.05f;message.what = ACTION_SWIPE;handler.sendMessageDelayed(message,100);}}};private int index = 0;private float swipeProgress = 0.0f;private KrcListView krcListView;private static final int ACTION_SWIPE = 1;private static final int ACTION_SCROLL = 2;private static final int ACTION_REMOVE_TOP = 3;private static final int ACTION_SCROLL_CENTER = 4;private static final String[] strList = new String[]{"对这个世界如果你有太多的抱怨","跌倒了就不敢继续往前走","为什麽人要这麽的脆弱 堕落","请你打开电视看看","多少人为生命在努力勇敢的走下去","我们是不是该知足","珍惜一切 就算没有拥有","还记得你说家是唯一的城堡","随着稻香河流继续奔跑","微微笑 小时候的梦我知道","不要哭让萤火虫带着你逃跑","乡间的歌谣永远的依靠","回家吧 回到最初的美好","陈湘制作QQ:123154129","不要这麽容易就想放弃","就像我说的","追不到的梦想","换个梦不就得了","为自己的人生鲜艳上色","先把爱涂上喜欢的颜色","笑一个吧 功成名就不是目的","让自己快乐快乐这才叫做意义","童年的纸飞机","现在终於飞回我手里","所谓的那快乐","赤脚在田里追蜻蜓追到累了","偷摘水果被蜜蜂给叮到怕了","谁在偷笑呢","我靠着稻草人吹着风唱着歌睡着了","哦 哦 午后吉它在虫鸣中更清脆 "};

下面是控制滚动的ViewGroup代码,滚动的原理是Scroller:
public class KrcListView extends LinearLayout {

public KrcListView(Context context) {this(context,null,0);
}public KrcListView(Context context, AttributeSet attrs) {this(context, attrs,0);
}public KrcListView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mScroller = new Scroller(context);init();
}public void scrollToCenter() {
//滚动到中心,使第一行的歌词居中scrollTo(0, -getHeight() / 2 + getHeight() / (2 * MAX_SIZE));int childCount = getChildCount();int height = getHeight();for (int i = 0; i < childCount; i++) {KrcView krcView = (KrcView) getChildAt(i);//设置每行歌词的高度krcView.getLayoutParams().height = height / MAX_SIZE;//滚动到中心时,所有歌词可见(因为滚动一行之后,顶部的歌词会不可见,所以重置一下)if(krcView.getVisibility() != VISIBLE)krcView.setVisibility(VISIBLE);if(krcView.getNoCurrentAlpha() < 255){krcView.setNoCurrentAlpha(1.0f);krcView.invalidate();}}
}@Override
public void computeScroll() {super.computeScroll();if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), mScroller.getCurrY());invalidate();}
}private void init() {setOrientation(VERTICAL);
}public void setChildPaint(int index) {int childCount = getChildCount();for (int i = 0; i < childCount; i++) {KrcView krcView = (KrcView) getChildAt(i);krcView.isCurrent = index == i;int distance = Math.abs(index - i);//离当前歌词距离越远,画笔越透明float alpha = 1.0f - 0.05f * distance;krcView.setNoCurrentAlpha(alpha);krcView.invalidate();}
}public void scrollSingleHeight() {if(getChildCount()==0)return;int childHeight = getChildAt(0).getHeight();mScroller.startScroll(0,getScrollY(),0,childHeight,1000);invalidate();
}
/**设置顶部的歌词不可见
**/
public void setTopInvisible(int index) {int topIndex = index-5;if(topIndex >= 0){getChildAt(topIndex).setVisibility(INVISIBLE);}
}private Scroller mScroller;
public static final int MAX_SIZE = 11;

最后是歌词的view代码:

public class KrcView extends View {public KrcView(String krc, Context context) {super(context);this.context = context;lineStr = krc;init();}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);int height = getHeight();//根据父布局给他的高度,适配字体大小float textSize = height*0.62f;noCurrentPaint.setTextSize(textSize);currentPaint.setTextSize(textSize);currentPassPaint.setTextSize(textSize);//计算字体高度,ondraw时drawText用到,详细可见我之前的博客Paint.FontMetrics fontMetrics = currentPassPaint.getFontMetrics();textHeight = (int) Math.ceil(fontMetrics.bottom - fontMetrics.top);bottomY = fontMetrics.bottom;textWidth = (int) currentPassPaint.measureText(lineStr);}public void setNoCurrentAlpha(float alpha) {noCurrentPaint.setAlpha((int) (alpha*256));}public int getNoCurrentAlpha() {return noCurrentPaint.getAlpha();}public void swipeProgress(float swipeProgress) {isCurrent = true;progress = swipeProgress;}private void init() {//初始化非当前歌词的画笔noCurrentPaint = new TextPaint();noCurrentPaint.setAntiAlias(true);noCurrentPaint.setColor(Color.parseColor("#ffffff"));noCurrentPaint.setTextAlign(Paint.Align.CENTER);//初始化当前歌词的画笔currentPaint = new TextPaint();currentPaint.setAntiAlias(true);currentPaint.setColor(Color.parseColor("#ffffff"));currentPaint.setTextAlign(Paint.Align.CENTER);//初始化当前歌词扫描的画笔(黄色)currentPassPaint = new TextPaint();currentPassPaint.setAntiAlias(true);currentPassPaint.setColor(Color.parseColor("#ffffff00"));currentPassPaint.setTextAlign(Paint.Align.CENTER);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//如果是当前的歌词,则需要画两边,一遍是普通的,一遍是扫描的if(isCurrent){canvas.drawText(lineStr, getWidth() / 2, getHeight() / 2 + textHeight / 2 - bottomY, currentPaint);canvas.save();canvas.clipRect(0, 0, getWidth() / 2 - textWidth / 2 + textWidth * progress, getHeight());canvas.drawText(lineStr,getWidth()/2,getHeight() / 2 + textHeight / 2-bottomY,currentPassPaint);canvas.restore();}else{canvas.drawText(lineStr,getWidth()/2,getHeight() / 2 + textHeight / 2-bottomY,noCurrentPaint);}}private String lineStr;private int textHeight;private int textWidth;private float bottomY = 0;private TextPaint currentPaint;private TextPaint currentPassPaint;private TextPaint noCurrentPaint;private float progress = 0.0f;public boolean isCurrent = true;private Context context;}

仿酷狗歌词的滚动效果相关推荐

  1. android歌词效果,Android仿酷狗动感歌词(支持翻译和音译歌词)显示效果

    引言 该开源依赖库是乐乐音乐播放器里的一个歌词模块功能,现在把该功能模块独立出来进行优化,并弄成了一个开源依赖库,其它音乐播放器项目只要引用该库并调用接口,便可轻松实现与乐乐音乐播放器一样的动感歌词显 ...

  2. Android仿酷狗动感歌词(支持翻译和音译歌词)显示效果

    引言 该开源依赖库是乐乐音乐播放器里的一个歌词模块功能,现在把该功能模块独立出来进行优化,并弄成了一个开源依赖库,其它音乐播放器项目只要引用该库并调用接口,便可轻松实现与乐乐音乐播放器一样的动感歌词显 ...

  3. java仿酷狗音乐源码_【附项目源码】仿酷狗音乐客户端,浅淡动感歌词补充

    原标题:[附项目源码]仿酷狗音乐客户端,浅淡动感歌词补充 1.前言 之前写了几篇关于动感歌词的简单介绍,相信大家还有印象,这里就不多说了,这篇要说的是,关于翻译歌词和音译歌词,以及我在解析和显示这两种 ...

  4. php手机端 调用音乐播放器,HTML_仿酷狗html5手机音乐播放器主要部分代码,HTML5作品,经测试,效果确定 - phpStudy...

    仿酷狗html5手机音乐播放器主要部分代码 HTML5作品,经测试,效果确定不错,遗憾的是只支持谷歌和苹果等以webkit核心的浏览器,网友体验的时候请使用谷歌等浏览器来运行,不然的话无法看到效果,不 ...

  5. Android耳机线控详解,蓝牙耳机按钮监听(仿酷狗线控效果)

    转载请注明出处:http://blog.csdn.net/fengyuzhengfan/article/details/46461253 当耳机的媒体按键被单击后,Android系统会发出一个广播,该 ...

  6. 【游戏开发创新】手把手教你使用Unity制作一个高仿酷狗音乐播放器,滨崎步,旋律起,爷青回(声音可视化 | 频谱 | Audio)

    文章目录 一.前言 二.获取UI素材 三.使用UGUI制作界面 1.界面布局 2.账号圆形头像 3.搜索框 4.调节UI层 5.黑色按钮悬浮高亮效果 6.纯文字按钮 7.滚动列表自适应 8.歌名与视频 ...

  7. 仿酷狗音乐播放器已开源!

    转载请说明原出处,谢谢:http://blog.csdn.net/zhuhongshu/article/details/41037875 距离我发布测试版的Redrain音乐盒(仿酷狗播放器),现在正 ...

  8. 仿酷狗音乐播放器开发日志十四——右侧乐库的实现

    在使用酷狗播放器时,左侧功能块和右侧乐库功能是最常用的了,如果要下载音乐或者搜索自己喜欢的歌曲那就少不了右侧乐库.原版的乐库的截图如下     他拥有5个分类,分别是乐库.电台.MV.直播.歌词.从外 ...

  9. 仿酷狗音乐播放器开发日志二十四 选项设置窗体的实现(附328行xml布局源码)

    转载请说明原出处,谢谢~~ 花了两天时间把仿酷狗的选项设置窗体做出来了,当然了只是做了外观.现在开学了,写代码的时间减少,所以整个仿酷狗的工程开发速度减慢了.今天把仿酷狗的选项设置窗体的布局代码分享出 ...

最新文章

  1. reportNG定制化之失败截图及日志
  2. python怎么字体加阴影_如何在pythonptx中给文本添加阴影?
  3. Python语言的程序结构
  4. php上传文件到七牛云源码,laravel上传文件到七牛云存储
  5. 游戏必备组件有哪些_面试必备:2019Vue经典面试题总结(含答案)
  6. 卡尔曼滤波器(Kalman Filter) 理解
  7. ueditor上传图片回调_springboot+mybatis+oss整合ueditor
  8. 评分卡模型开发(三)--数据集准备
  9. html5 序列帧播放器,Pdplayer 64位版(序列帧动画播放器)V1.0.7.33 免费版
  10. cad填充密度怎么调整_CAD填充图案放在哪里,这几步你要了解
  11. 年会抽奖程序:200行HTML+JavaScript写个桌面程序
  12. WIN10 任务栏卡死解决办法
  13. 姜小白的python日记Day4 列表和元组
  14. 设备维保管理系统对于设备正常运行的重要性!
  15. PC端微信登录实现流程
  16. 电脑其实很好玩,玩好了其实很无耻
  17. CSS设置高斯模糊效果
  18. html文件剖析 - mdn学习
  19. 优秀程序员的18大法则-兄弟连IT教育
  20. 利用qt打开一张图片并转成灰度矩阵

热门文章

  1. 快手光合计划完整版攻略
  2. 微信小程序——map用法
  3. 平板电脑性价比排行2022
  4. 谷粒商城 - 微服务分布式电商项目
  5. 大恒相机开发实践(3)——参数设置
  6. 百度ueditor粘贴word图片且图片文件自动上传功能
  7. 陶渊明笔下的桃花源就在此,连郭沫若都赞不绝口
  8. 上海“富爸爸” 神奇投资之路
  9. 二维码插件qrcode生成二维码信息
  10. ROS机器人入门课程《ROS理论与实践》零基础教程(推荐课程)