今天将为大家带来 粗略版 酷狗音乐 歌词播放的效果。我们一步一步来。首先做这个是因为有一次公司项目中需要做一个汽车扫描效果的时候,想到来做这个歌词播放效果的。那么我们这次先上效果图:

好的上面的文字是我们要实现的效果,在那之前先说说这个汽车扫描的实现,这样或许更容易理解后面的歌词播放原理。好的,那么我先开始汽车扫描部分的思路说明,先上代码:

package com.example.scanview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

public class CarCheckView extends View {
/**
* 定义背景bitmap,扫描过后的bitmap和扫描线
*/
private Bitmap car, lineCar, line;
/**
* 画笔
*/
private Paint paint;
/**
* 图形操作工具类
*/
private Matrix matrix;
/**
* Y坐标
*/
private int y = 60;
/**
* 是否正在扫描
*/
private boolean isCanning = false;

public CarCheckView(Context context) {super(context);initData();
}public CarCheckView(Context context, AttributeSet attrs) {super(context, attrs);initData();
}/*** 注意了:美工切图时car和carline这两个图的宽高大小要一致*/
private void initData() {car = BitmapFactory.decodeResource(getResources(), R.drawable.car);lineCar = BitmapFactory.decodeResource(getResources(), R.drawable.carline);line = BitmapFactory.decodeResource(getResources(), R.drawable.check_line);paint = new Paint();paint.setAntiAlias(true);matrix = new Matrix();
}public boolean isCanning() {return isCanning;
}/*** @param isCanning* *            true 开始扫描 : false 停止扫描*/
public void setScan(boolean isCanning) {this.isCanning = isCanning;if (isCanning) {} else {y = 60;}postInvalidate();
}@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);matrix.reset();// 不断得扫描if (y <= car.getHeight())y += 3;elsey = 60;if (isCanning) {// 如果开始扫描了,才显示扫描线,和扫描后的bm/*** draw扫描后出现的bm,这里无需改变*/canvas.drawBitmap(lineCar, matrix, paint);// 三个参数的,默认为left:0,top:0/*** 最后draw扫描线,这里扫描线的位置要相对于car居中,所以取car和line的宽度的一半就是*/canvas.drawBitmap(line, (car.getWidth() - line.getWidth()) / 2, y - (line.getHeight() >> 1), paint);invalidate();}/*** draw扫描后逐渐隐藏的bm,这里要对Y(top)作改变*/scanImage(canvas, car, y);}private void scanImage(Canvas canvas, Bitmap bm, int y) {Rect src = new Rect();Rect dst = new Rect();src.left = 0;src.top = y;src.right = bm.getWidth();src.bottom = bm.getHeight();dst.left = 0;dst.top = y;dst.right = bm.getWidth();dst.bottom = bm.getHeight();canvas.drawBitmap(bm, src, dst, paint);
}@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(car.getWidth(), car.getHeight());
}

}

那么首先这个是一个自定义的view,我们先写一个CarCheckView继承于View,然后在初始化的时候先初始化一些必要的数据。看上面的效果图可以发现,该view需要绘制3个图,要准备3张切图资源,一个是真实车身图,另外一个是线型车身图,还有就是一条扫描线了。

那么这边主要就对ondraw()方法进行说明,在ondraw()方法中我们要考虑的是先绘制哪一张图,一定要注意绘制的顺序,看效果真实车身是在最上面的,所以这个最后再来draw,其它2个则不用考虑,然后车身图跟线型车身图的宽高大小是一致的,位置也是一致的,还有就是设置扫描线的位置,具体在代码中也有注释说明。扫描线是draw在车身上面再高一点的距离,然后慢慢向下进行扫描,
所以这边draw线的Y坐标是个变量,而且跟draw感觉大小可变的真实车身图的Y坐标是一致的,那么draw真实车身,这边我们需要用带4个参数的方法进行绘制了,这4个参数的作用代码中已作说明,因为我们是由上往下进行一个扫描效果,那么我们就控制draw真实车身图的区域和显示在屏幕上的区域,即是中间的那两个参数所表示的区域,这边这样说可能比较难于理解,大家可以代入不同的值进行设置再看看效果即可。最后再设置一些临界值就可以了,扫描线超过车身时,从新退回来继续扫描,设置扫描开始,扫描结束等,那么这样就完成了汽车扫描部分了。

好了,那么说到这里的时候,不知各位同学是否已经对歌词播放效果的实现有了一定的思路了呢?

那么下面开始我们的歌词播放效果部分内容,还是一样先上代码:

package com.example.scanview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MyGround extends RelativeLayout {
private TextView redText, blueText;
private Bitmap blueBitmap;
private Bitmap redBitmap;
private Paint paint;
/**
* 是否正在播放歌词
*/
private boolean isSinging = false;
private int left = 0;

public MyGround(Context context) {super(context);initPaint();
}public MyGround(Context context, AttributeSet attrs) {super(context, attrs);initPaint();
}private void initPaint() {paint = new Paint();paint.setStrokeWidth(5);paint.setColor(Color.BLACK);
}/*** viewgroup若是要实现wrap_content效果,则应该先测量子view的大小,然后根据子view的大小再去测量自身的大小* * 如果直接测量自身的大小会占屏幕宽高* * 要想父view的大小随子view的宽高变化而变化,必须先测量子view的大小*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 直接测量自身大小// int measureWidth = getMeasureWHSize(widthMeasureSpec);// int measureHeight = getMeasureWHSize(heightMeasureSpec);// setMeasuredDimension(measureWidth, measureHeight);for (int i = 0; i < getChildCount(); i++) {View v = getChildAt(i);v.measure(widthMeasureSpec, heightMeasureSpec);}setMeasuredDimension(getChildAt(0).getMeasuredWidth(), getChildAt(0).getMeasuredHeight());
}/*** 获取测量值* * @param measureSpec* @return*/
private int getMeasureWHSize(int measureSpec) {int result = 0;int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);switch (mode) {case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = size;break;}return result;
}@Override
/*** 默认会执行两次*/
protected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);// 当布局发生改变时,才向下执行if (!changed)return;int childs = getChildCount();for (int i = 0; i < childs; i++) {View v = getChildAt(i);v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());}if (redBitmap == null || blueBitmap == null) {redText = (TextView) findViewById(R.id.text1);blueText = (TextView) findViewById(R.id.text2);redBitmap = getBitmapByView(redText);blueBitmap = getBitmapByView(blueText);redText.setVisibility(View.INVISIBLE);blueText.setVisibility(View.INVISIBLE);}
}private Bitmap getBitmapByView(View view) {view.setDrawingCacheEnabled(true);view.buildDrawingCache();return view.getDrawingCache();
}@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);
}@Override
protected void onDraw(Canvas canvas) {drawBackgroupText(canvas);drawFrontgroupText(canvas);
}/*** canvas.drawBitmap(bitmap, src, dst,paint) <br/>* 参数1、 位图 <br/>* 参数2、 为要画的bitmap的区域 <br/>* 参数3、为要显示在屏幕上的区域,即是绘制在屏幕的什么地方 <br/>* 参数4、画笔 <br/>* * @param canvas*/
private void drawFrontgroupText(Canvas canvas) {Rect srcBlue = new Rect();Rect dstBlue = new Rect();srcBlue.left = left;srcBlue.top = 0;srcBlue.right = blueBitmap.getWidth();srcBlue.bottom = blueBitmap.getHeight();dstBlue.left = left;dstBlue.top = 0;dstBlue.right = blueBitmap.getWidth();dstBlue.bottom = blueBitmap.getHeight();canvas.drawBitmap(blueBitmap, srcBlue, dstBlue, paint);if (isSinging) {left++;if (left <= srcBlue.right)invalidate();}
}private void drawBackgroupText(Canvas canvas) {Rect srcRed = new Rect();Rect dstRed = new Rect();srcRed.left = 0;srcRed.top = 0;srcRed.right = redBitmap.getWidth();srcRed.bottom = redBitmap.getHeight();dstRed.left = 0;dstRed.top = 0;dstRed.right = redBitmap.getWidth();dstRed.bottom = redBitmap.getHeight();canvas.drawBitmap(redBitmap, srcRed, dstRed, paint);
}/*** @param isSinging* *            true 开始播放歌词 : false 停止播放歌词*/
public void setSing(boolean isSinging) {this.isSinging = isSinging;left = 0;postInvalidate();
}public boolean isSinging() {return isSinging;
}

}
这边我是这样做的,如果其他大虾有更好更容易的方法,请多多赐教。我们这边为什么要继承于ViewGroup?回看汽车扫描部分的代码,draw那个车身大小可变的车身图所用到的canvas的方法所接收的参数是一个bitmap类型,那么歌词是可变的,我们总不可能叫美工切歌词的图,既然这样那我们只能用文本可随时变化的textview了

好的,这边的实现跟汽车扫描部分的实现原理基本上是一样的。那么我们只看其中几个不同的地方和需要注意的细节问题。

好了,我们先在textview中设置要播放的歌词,再调用上面的方法getBitmapByView获取view的缩略图,再将textview隐藏掉,然后在textview的位置draw上刚刚获取的view的缩略图就可以了,这边是要两个textview来存放的,一个是未播放时的颜色,另一个是播放过后的颜色,当播放完毕的时候再从新操作一遍就可以了,我这边为了方便省事就没去做了,

还有得就是汽车扫描部分是从上到下,而歌词播放部分则是由左及右,变量改成left即可,另外还需注意的地方就是,我们这个viewgroup的宽高大小要依据于这两个textview的大小来定量,所以在onMeasure()方法中我们要先去测量两个子Textview的大小,然后获取两个子textview的测量大小来设置viewgroup自身的测量值。

另外viewgroup一开始时的onMeasure会连续执行2次,onlayout执行一次,然后onMeasure再执行2次,onlayout再执行一次,考虑到性能方面大家可以自己作标志让其只加载一次就好,当然我这边也没做,图省事了。

好了,还有最后一个需要注意的地方,因为我们这个是自定义Viewgroup,跟自定义view还是有差距的,自定义view的view启动时ondraw()方法默认会启动一次,而Viewgroup的则不会,但是在xml布局时设置上Viewgroup的背景则会执行,这个我在这里也解释不了,估计要去查看源码才能说明了。

好了,到这里基本上大功告成了!

源码点击下载

实现 酷狗音乐 歌词播放效果相关推荐

  1. 学习笔记--实现类似酷狗音乐歌词的效果

    一直以来都是,想起一个问题了,就网上查资料,就看别人的博客.这样发现好多时候,其实这个问题以前查过了,每次都得浪费精力再查,而且结果还不一定好.所以呢,以后遇到问题还是要找个靠谱的地方记录下来,学着在 ...

  2. KRSReader酷狗音乐歌词写真图片提取工具(提取KRS文件中的图片)

    最近发现酷狗音乐中的歌词写真图片还是比较给力的,很多友友表示喜欢,但是苦于不懂得如何提取,小菜利用周末闲暇时间写了一个小工具,专门用来提取酷狗音乐歌词写真图片. 废话不多说,软件界面如下: 使用说明: ...

  3. Qt模仿酷狗音乐的播放图标

    手机酷狗音乐在播放的时候,中间有一个旋转图标,显示播放进度,如下所示. Qt模仿酷狗音乐的播放图标效果图: 头文件 #ifndef QWHKUGOUMUSICLABEL_H #define QWHKU ...

  4. 关于酷狗音乐无法播放音乐,显示音频驱动异常的问题

    关于酷狗音乐无法播放音乐,显示音频驱动异常的问题 方法一:用鲁大师的驱动监测,查看声卡是否需要更新或者安装. 方法二:对"我的电脑"(或者"此电脑")右键点击& ...

  5. 【前端基础小案例】HTML+CSS实现酷狗音乐热榜效果

  6. 计算机快捷键弹音乐,电脑怎样用快捷键弹出酷狗音乐播放界面

    2018-04-03 电脑没声音 放酷狗音乐 在播放 但没声音 电脑没声音请按以下方案逐条排查应可解决(注意顺序),满意请采纳: ? ? ★第1步:检查右下角小喇叭还在不,音量是否关到最小了或是被选择 ...

  7. php中文歌词,将酷狗krc歌词解析并转换为lrc歌词php源码

    最近在进行一次对酷狗音乐歌词采集时发现酷狗音乐的歌词直接浏览都是"乱码",自己平时所见的歌词都是lrc格式的文本,这种酷狗专用的krc格式的显然是经过特别处理过的,平时用酷狗听音乐 ...

  8. Android获取酷狗音乐歌曲详细信息

    Android获取酷狗音乐歌曲详细信息 一.目标 二.实现方案 三.最终方案 四.网易云音乐 五.遗留问题 六.接下来 七.Finally 在<Android获取歌曲详细信息>一文中,介绍 ...

  9. 酷狗音乐接口开放程度令人咂舌

    一.前言 事情是这样的,今天本来打算听听音乐,不自觉的就想起了以前最爱听的那首歌曲-------洋葱,一首有点伤感的歌曲,不禁想起了江浙一带的前女友,虽然结果现实而又无奈,但是歌曲是真的好听,那么今天 ...

最新文章

  1. Python3协程(coroutine)理解
  2. 存储如何让文件小一点_如何使用Redis接管文件存储
  3. 吉林大学计算机高级程序设计笔记
  4. nginx多入口配置隐藏.php,Nginx配置tp5支持pathinfo以及隐藏入口文件
  5. linux 查看 shell进程,Linux之shell 和进程
  6. 【论文笔记】Joint Cascade Face Detection and Alignment
  7. xp系统蓝屏代码7b_电脑蓝屏的症状和解决办法
  8. 找出两个矩阵不同的元素_推荐系统传统推荐模型之矩阵分解
  9. 保研之路——北航网安学院直硕夏令营
  10. PBFT(一):过程
  11. 税控盘是服务器系统,税控盘系统设置服务器地址
  12. 不懂PS怎么修改图片尺寸?
  13. 用微博图片反查上传者信息
  14. Android图片轮播控件
  15. linux下pdb文件除水,blast+本地化中blastp操作(基于PDB库)—linux
  16. C++ 有关string类的基本语法以及一个简单算法 理论加案例的形式
  17. 牛顿法来解最大似然估计
  18. 抓取国家统计局网站上的最新县及县以上行政区划代码,并保存成json格式的文件
  19. 常见CAD/CAM控件大全
  20. 树莓派远程视频监控的移植pistreaming

热门文章

  1. 月末关账流程和政策规定
  2. Linux安装及美化Typora详细步骤
  3. 3个方法恢复彻底删除的苹果手机视频!
  4. PowerPivot的杀手锏是什么?
  5. 25 条客户服务名言激励您的团队
  6. ADB模拟点击、滑动事件
  7. 利用TI的官网Sysconfig配置beagleboard-x15 linux系统中的串口
  8. 分手后怎样才能让前任重回你身边
  9. 寒江独钓前辈的第一个例子的编译运行过程
  10. QString, QByteArray, 和 QVariant用法详解