最近由于項(xiàng)目的需要,要做個(gè)類似荔枝FM首頁音頻播放的動(dòng)態(tài)顯示控件,就是幾根柱體有規(guī)律的上下浮動(dòng)惋耙。一開始想到的是使用幀動(dòng)畫實(shí)現(xiàn),這就要辛苦UI妹子動(dòng)手切幾個(gè)好看的圖熊昌,然后往應(yīng)用上一丟就噢了绽榛。不過看過效果后,結(jié)果總是差強(qiáng)人意婿屹,最終還是選擇使用自定義View來實(shí)現(xiàn)灭美。
首先來看看要實(shí)現(xiàn)的效果,截圖如下:
原理
接著來看看實(shí)現(xiàn)的原理昂利,主要是View的繪制冲粤,對View的繪制主要在onDraw(canvas)中使用canvas畫布和paint畫筆對View進(jìn)行不同形狀的繪制。
主要所涉及的類:
- canvas 畫布页眯,指定形狀Rect或是坐標(biāo)XY使用Paint作畫
- Paint 畫筆,設(shè)置Color(畫筆顏色)厢呵,style(填充方式)窝撵,storkeWidth(畫筆大小)等
- Rect (top left bottom right)坐標(biāo)參數(shù) 上左下右
- Bitmap 圖片
形狀大致分為如下幾種:
- point 點(diǎn)
- line 線
- rect 矩形/正方形
- oval 橢圓
- circle 圓
- arc 扇形
- roundRect 圓角矩形
- path 路徑(如三角形)
- bitmap 圖片
更多關(guān)于Canvas的內(nèi)容襟铭,可以參考博客 Android自定義View高級(三)-Canvas之畫布操作,這里就不詳細(xì)講述了碌奉。
好了,我們看回開篇的話題寒砖,如何實(shí)現(xiàn)動(dòng)態(tài)的音頻柱體赐劣。
Init 初始化
// 獲取attrs設(shè)置的屬性,可以在布局中使用這些屬性做初始化
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BeatLoadView);
mPaintColor = typedArray.getColor(R.styleable.BeatLoadView_paintColor, Color.GRAY);
mStrokeWidth = typedArray.getDimension(R.styleable.BeatLoadView_strokeWidth, dp2px(5));
mHeight = typedArray.getDimension(R.styleable.BeatLoadView_itemHeight, dp2px(20));
mPadding = typedArray.getDimension(R.styleable.BeatLoadView_itemsPadding, dp2px(7));
typedArray.recycle();
mPaint = new Paint(); // 創(chuàng)建畫筆
mPaint.setColor(mPaintColor); // 設(shè)置顏色
mPaint.setAntiAlias(true); // 抗鋸齒
mPaint.setStrokeWidth(mStrokeWidth); // 設(shè)置描邊寬度
mPaint.setStyle(Paint.Style.FILL); // 設(shè)置填充方式
paddingOne = mPadding; // 邊距哩都,這是柱體間的間距
paddingSecond = mPadding * 2;
paddingThird = mPadding * 3;
reset();
重置參數(shù)
private void reset() {
// 三個(gè)柱體開始高度(Y的開始坐標(biāo))這里設(shè)置的是3的倍數(shù)魁兼,這樣繪制時(shí)就是遞增遞減
lineOneStartY = mHeight / 1.5f; // 第一根柱體開始的Y坐標(biāo)
lineOneEndY = mHeight; // 第一根柱體結(jié)束的Y坐標(biāo)
lineSecondStartY = mHeight / 3;
lineSecondEndY = mHeight;
lineThirdStartY = mHeight / 6;
lineThirdEndY = mHeight;
onePlus = true; // 第1根柱體高度值加減的標(biāo)志
secondPlus = true; // 第2根柱體高度值加減的標(biāo)志
thirdPlus = true; // 第3根柱體高度值加減的標(biāo)志
}
開啟線程不停的繪制
// 內(nèi)部初始化時(shí)調(diào)用開始繪制或者可以設(shè)置在外部調(diào)用開啟繪制
mThread = new Thread() {
@Override
public void run() {
while (true) {
if (running)
postInvalidate(); // 子線程中調(diào)用該方法就會不停的調(diào)用onDraw進(jìn)行繪制 ,UI線程則調(diào)用invalidate()
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
mThread.start();
onDraw 關(guān)鍵方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!running) { // 停止時(shí)重置參數(shù)
reset();
}
// 繪制第一個(gè)柱體
canvas.drawLine(paddingOne, lineOneStartY, paddingOne, lineOneEndY, mPaint);
// 第二個(gè)
canvas.drawLine(paddingSecond, lineSecondStartY, paddingSecond, lineSecondEndY, mPaint);
// 第三個(gè)
canvas.drawLine(paddingThird, lineThirdStartY, paddingThird, lineThirdEndY, mPaint);
//========================================================
// 根據(jù)onePlus來設(shè)置Y坐標(biāo)開始值的自增自減
if (onePlus) {
lineOneStartY++;
} else {
lineOneStartY--;
}
// 臨界條件的判斷
if (lineOneStartY >= mHeight) { // 當(dāng)Y開始值自增>=指定的最大高度漠嵌,此時(shí)Y開始值應(yīng)該自減
onePlus = false;
} else if (lineOneStartY <= 0) { // 當(dāng)Y開始值自減<=0時(shí)咐汞,此時(shí)Y開始值應(yīng)該自增
onePlus = true;
}
//========================================================
// 第二個(gè) ========================================================
if (secondPlus) {
lineSecondStartY++;
} else {
lineSecondStartY--;
}
if (lineSecondStartY >= mHeight) {
secondPlus = false;
} else if (lineSecondStartY <= 0) {
secondPlus = true;
}
// 第二個(gè) ========================================================
// 第三個(gè) ========================================================
if (thirdPlus) {
lineThirdStartY++;
} else {
lineThirdStartY--;
}
if (lineThirdStartY >= mHeight) {
thirdPlus = false;
} else if (lineThirdStartY <= 0) {
thirdPlus = true;
}
// 第三個(gè) ========================================================
}
xml使用
<com.gm.load.widget.BeatLoadView
android:id="@+id/beat_view"
android:layout_width="28dp"
android:layout_height="25dp"
android:layout_margin="12dp"
app:paintColor="@android:color/holo_orange_light" />
beatLoadView.setDrawRunning(isRunning) // 控制繪制
完整代碼,可以到本人github上download儒鹿,歡迎關(guān)注和star