Android簡單自定義音樂波動特效圖
本文實例為大家分享了Android簡單自定義音樂波動特效圖的具體代碼,供大家參考,具體內(nèi)容如下
最終效果:

思路:就是繪制一個不斷變化高度的矩形或者是寬虛線
1.自定義屬性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="musicPlayViewAttr">
<!--指針顏色-->
<attr name="point_color" format="color" />
<!--指針數(shù)量-->
<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 {
//坐標(biāo)原點x
private float mBasePointX;
//坐標(biāo)原點y
private float mBasePointY;
//指針的數(shù)量 默認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);
}
/**
* 設(shè)置指針高度和即那個
*/
@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;//控制子線程中的循環(huán)
}
}
/**
* 停止線程 停止播放
*/
public void stop() {
setVisibility(INVISIBLE);
mIsPlaying = false;
invalidate();
}
/**
* 更新UI
*/
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
invalidate();
}
};
/**
* 子線程,循環(huán)改變每個指針的高度
*/
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));//隨機數(shù)
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轉(zhuǎn)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;
}
}
}
因為注釋都挺詳細的,就沒有做太多的介紹,我這里也只是提供一個思路,里面有很多可以優(yōu)化的地方比方說線程使用和循環(huán)的時候,如果有不懂的地方可以留言。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
android利用ContentResolver訪問者獲取手機聯(lián)系人信息
這篇文章主要介紹了android利用ContentResolver訪問者獲取手機聯(lián)系人信息,非常具有實用價值,需要的朋友可以參考下。2017-02-02
Android 深入探究自定義view之流式布局FlowLayout的使用
FlowLayout(int align, int hgap, int vgap)創(chuàng)建一個新的流布局管理器,它具有指定的對齊方式以及指定的水平和垂直間隙,意思就是說從左上角開始添加原件,依次往后排,第一行擠滿了就換一行接著排2021-11-11
Android 自動化測試經(jīng)驗分享 UiObejct.getFromParent()的使用方法
本篇文章對Android中UiObejct.getFromParent()的使用進行了詳細的分析介紹。需要的朋友參考下2013-05-05
Android基于Sensor感應(yīng)器獲取重力感應(yīng)加速度的方法
這篇文章主要介紹了Android基于Sensor感應(yīng)器獲取重力感應(yīng)加速度的方法,涉及Android使用Sensor類實現(xiàn)感應(yīng)重力變化的功能,需要的朋友可以參考下2015-12-12
Android 日常開發(fā)總結(jié)的60條技術(shù)經(jīng)驗
這篇文章主要介紹了Android日常開發(fā)總結(jié)的技術(shù)經(jīng)驗60條,需要的朋友可以參考下2016-03-03

