Android简单自定义音乐波动特效图
作者:浪克oo 发布时间:2022-10-09 15:45:44
标签:Android,音乐波动
本文实例为大家分享了Android简单自定义音乐波动特效图的具体代码,供大家参考,具体内容如下
最终效果:
思路:就是绘制一个不断变化高度的矩形或者是宽虚线
1.自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="musicPlayViewAttr">
<!--指针颜色-->
<attr name="point_color" format="color" />
<!--指针数量-->
<attr name="point_num" format="integer" />
<!--指针宽度-->
<attr name="point_width" format="float" />
<!--指针波动速度-->
<attr name="point_speed" format="integer" />
</declare-styleable>
</resources>
2.编写自定义MusicPlayview
/**
* 音乐播放波动动画
*/
public class MusicPlayView extends View {
//坐标原点x
private float mBasePointX;
//坐标原点y
private float mBasePointY;
//指针的数量 默认10
private int mPointNum;
//指针间的间隙 默认5dp
private float mPointSpace;
//每个指针的宽度 默认5dp
private float mPointWidth;
//指针的颜色
private int mPointColor = Color.RED;
//指针的集合
private List<Pointer> mPoints;
//控制开始/停止
private boolean mIsPlaying = false;
//播放线程
private Thread mPlayThread;
//指针波动速度
private int mPointSpeed;
//画笔
private Paint mPaint;
public MusicPlayView(Context context) {
super(context);
init();
}
public MusicPlayView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//取出自定义属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.musicPlayViewAttr);
mPointNum = ta.getInt(R.styleable.musicPlayViewAttr_point_num, 10);
mPointWidth = dp2px(getContext(),
ta.getFloat(R.styleable.musicPlayViewAttr_point_width, 5f));
mPointColor = ta.getColor(R.styleable.musicPlayViewAttr_point_color, Color.RED);
mPointSpeed = ta.getInt(R.styleable.musicPlayViewAttr_point_speed, 40);
init();
}
public MusicPlayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.musicPlayViewAttr);
mPointNum = ta.getInt(R.styleable.musicPlayViewAttr_point_num, 10);
mPointWidth = dp2px(getContext(), ta.getFloat(R.styleable.musicPlayViewAttr_point_width, 5f));
mPointColor = ta.getColor(R.styleable.musicPlayViewAttr_point_color, Color.RED);
mPointSpeed = ta.getInt(R.styleable.musicPlayViewAttr_point_speed, 40);
init();
}
/**
* 初始化画笔
*/
private void init() {
mPoints = new ArrayList<>();
//绘制虚线
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(mPointColor);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(mPointWidth);
mPaint.setPathEffect(new DashPathEffect(new float[]{25, 15}, 0));//虚线间隔
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
/**
* 设置指针高度和即那个
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//获取逻辑原点的Y
mBasePointY = getHeight() - getPaddingBottom();
Random random = new Random();
if (mPoints != null)
mPoints.clear();
for (int i = 0; i < mPointNum; i++) {
//随机高度
mPoints.add(new Pointer((float) (0.1 * (random.nextInt(10) + 1) * (getHeight() - getPaddingBottom() - getPaddingTop()))));
}
//计算每个指针之间的间隔 view宽度 - 左右的padding - 所有指针总共宽度 再除以多少个间隔
mPointSpace = (getWidth() - getPaddingLeft() - getPaddingRight() - mPointWidth * mPointNum) / (mPointNum - 1);
}
/**
* 开始绘制虚线
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//指针x位置
mBasePointX = 0f + getPaddingLeft() + mPointWidth / 2;
//绘制每一个指针。
for (int i = 0; i < mPoints.size(); i++) {
//绘制虚线
float[] pts = {mBasePointX, getHeight(), mBasePointX, (mBasePointY - mPoints.get(i).getHeight())};//重下往上动画
canvas.drawLines(pts, mPaint);
//更新指针x位置
mBasePointX += (mPointSpace + mPointWidth);
}
}
/**
* 开始线程 播放
*/
public void start() {
setVisibility(VISIBLE);
if (!mIsPlaying) {
if (mPlayThread == null) {
mPlayThread = new Thread(new PlayRunnable());
mPlayThread.start();
}
mIsPlaying = true;//控制子线程中的循环
}
}
/**
* 停止线程 停止播放
*/
public void stop() {
setVisibility(INVISIBLE);
mIsPlaying = false;
invalidate();
}
/**
* 更新UI
*/
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
invalidate();
}
};
/**
* 子线程,循环改变每个指针的高度
*/
public class PlayRunnable implements Runnable {
@Override
public void run() {
for (float i = 0; i < Integer.MAX_VALUE; ) {
try {
for (int j = 0; j < mPoints.size(); j++) {
float rate = (float) Math.abs(Math.sin(i + j));//随机数
mPoints.get(j).setHeight((mBasePointY - getPaddingTop()) * rate); //每个指针的高度
}
Thread.sleep(mPointSpeed);//控制动画速度
//开始/暂停
if (mIsPlaying) {
myHandler.sendEmptyMessage(0);
i += 0.1;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 指针对象
*/
public class Pointer {
private float height;
public Pointer(float height) {
this.height = height;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
}
/**
* dp转px
*/
public static int dp2px(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources()
.getDisplayMetrics());
}
}
3.在activity_main2布局中使用MusicPlayView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.hk.testapplication.MusicPlayView
android:id="@+id/music_play"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible"
android:padding="10dp"
app:point_color="#F44336"
app:point_num="10"
app:point_width="14" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/bt_play"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="播放"/>
<Button
android:id="@+id/bt_stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="停止"/>
</LinearLayout>
</LinearLayout>
4.MainActivity中使用
public class MainActivity2 extends AppCompatActivity implements View.OnClickListener {
private Button mBtPlay,mBtStop;
private MusicPlayView mMusicPlayView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mMusicPlayView = findViewById(R.id.music_play);
mBtPlay = findViewById(R.id.bt_play);
mBtStop = findViewById(R.id.bt_stop);
mBtPlay.setOnClickListener(this);
mBtStop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_play:
//开始播放
mMusicPlayView.start();
break;
case R.id.bt_stop:
//停止播放
mMusicPlayView.stop();
break;
}
}
}
因为注释都挺详细的,就没有做太多的介绍,我这里也只是提供一个思路,里面有很多可以优化的地方比方说线程使用和循环的时候,如果有不懂的地方可以留言。
来源:https://blog.csdn.net/weixin_35959554/article/details/115719682


猜你喜欢
- 本文实例讲述了C#中timer定时器用法。分享给大家供大家参考。具体如下:下面的代码通过Timer定时器每隔1000毫秒(1秒)触发一次事件
- 本文实例讲述了Android中WebView用法。分享给大家供大家参考,具体如下:WebView相当于一个迷你浏览器,采用WebKit内核,
- 一、概述xml整合第三方框架有两种整合方案:不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,例如:MyBatis
- 笔者在使用Entity Framework中的Scaffolding机制自动创建拓展名为mdf的数据库及表单时,遇到如下的错误:A file
- 方式一:基于现有控件进行扩展,如基于button进行扩展,UI可直接用xmal进行编辑设计,逻辑用xaml.cs进行编辑方法二:直接创建wp
- 今天在用rsa界面服务端的数据时,碰到了部分乱码的问题,虽然能解密出正确的数据但是前面会多一堆乱码.一开始以为是编码的问题,可是全都设置成了
- AsyncTask不仅方便我们在子线程中对UI进行更新操作,还可以借助其本身的线程池来实现多线程任务。下面是一个使用AsyncTask来实现
- 本文实例讲述了Java爬取豆瓣电影数据的方法。分享给大家供大家参考,具体如下:所用到的技术有Jsoup,HttpClient。Jsoupjs
- 这篇文章主要介绍了Java自定义实现equals()方法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- android仿照qq的顶部栏效果,主要就是利用fragment manager把fragment设置显示内容(1)在activity_ma
- 一、前言java是一门跨硬件平台的面向对象高级编程语言,java程序运行在java虚拟机上(JVM),由JVM管理内存,这点是和C++最大区
- 实现如下边框效果:虚线画效果,可以使用Android中的xml来做。下面话不多说,直接上代码:<RelativeLayout &nbs
- 一、简介上篇介绍了一个自己做的管理系统,最近空闲的时间自己在继续做,把之前登录时候自定义的 * 过滤器换成了基于SpringSecurity
- 由于毕业后工作没有对接到专业问题,导致四五年没有碰过Winform程序了。突然由于工作问题,为了方便自己,所以想自己写写小winform小软
- Android手机震动抖动效果的实现(1)布局文件如下<RelativeLayout xmlns:android="http
- 本文实例为大家分享了Java图片验证码代码,供大家参考,具体内容如下网页显示效果:index.jsp 使用两种方式强制图片更新: 1、设置图
- 一、实现效果图关于贝塞尔曲线 二、实现代码1.自定义viewpackage com.czhappy.showintroduce.view;i
- 一、泛型的概念1.1 基础案例泛型在Java中的应用非常广泛,最常见则是在集合容器中,先看下基础用法:public class Generi
- 正式版:版本最新但只有14天的体验时间,之后需要激活,激活注册已经不行了,现在需要使用新的方式:首先下载反向代理工具,下载地址:根据系统选择
- 将脚本挂在要判断声音是否播放完毕的物体上using System.Collections;using UnityEngine;using U