Android简单自定义音乐波动特效图
作者:浪克oo 时间:2022-10-09 15:45:44
本文实例为大家分享了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
标签:Android,音乐波动
0
投稿
猜你喜欢
c# 递归访问文件夹(删掉歌词文件)
2022-02-11 02:52:16
Android使用WebView实现截图分享功能
2023-04-17 08:03:48
java通过Callable和Future来接收线程池的执行结果
2022-03-31 05:01:43
C++链表节点的添加和删除介绍
2023-08-23 02:32:09
史上最全图文讲解Java泛型
2022-08-23 20:27:47
C#使用listView增删操作实例
2023-03-25 12:34:52
原来Java中有两个ArrayList
2023-06-27 11:49:40
springboot中.yml文件参数的读取方式
2021-06-20 00:57:51
Spring Bean的包扫描的实现方法
2021-10-21 12:40:07
浅谈springioc实例化bean的三个方法
2022-05-18 08:37:56
java字符串常用操作方法(查找、截取、分割)
2023-11-29 03:21:13
值得Java开发者关注的7款新工具
2023-11-02 23:05:31
WPF如何绘制光滑连续贝塞尔曲线示例代码
2022-06-07 18:31:58
Android 拦截返回键事件的实例详解
2023-02-19 07:09:09
C语言中的指针以及二级指针代码详解
2022-09-04 21:40:28
Android仿支付宝支付从底部弹窗效果
2022-04-30 10:37:13
详解Android获取所有依赖库的几种方式
2023-12-13 05:41:51
Toast类避免显示时间叠加的方法
2021-08-20 02:01:42
Android实现与Apache Tomcat服务器数据交互(MySql数据库)
2023-06-02 21:53:39
Nacos 动态服务发现、配置和服务管理平台初体验
2022-09-10 23:56:53