最近由于项目的需要,要做个类似荔枝FM首页音频播放的动态显示控件,就是几根柱体有规律的上下浮动。一开始想到的是使用帧动画实现,这就要辛苦UI妹子动手切几个好看的图,然后往应用上一丢就噢了。不过看过效果后,结果总是差强人意,最终还是选择使用自定义View来实现。
首先来看看要实现的效果,截图如下:
a原理
接着来看看实现的原理,主要是View的绘制,对View的绘制主要在onDraw(canvas)中使用canvas画布和paint画笔对View进行不同形状的绘制。
主要所涉及的类:
- canvas 画布,指定形状Rect或是坐标XY使用Paint作画
- Paint 画笔,设置Color(画笔颜色),style(填充方式),storkeWidth(画笔大小)等
- Rect (top left bottom right)坐标参数 上左下右
- Bitmap 图片
形状大致分为如下几种:
- point 点
- line 线
- rect 矩形/正方形
- oval 椭圆
- circle 圆
- arc 扇形
- roundRect 圆角矩形
- path 路径(如三角形)
- bitmap 图片
更多关于Canvas的内容,可以参考博客 Android自定义View高级(三)-Canvas之画布操作,这里就不详细讲述了。
好了,我们看回开篇的话题,如何实现动态的音频柱体。
Init 初始化
// 获取attrs设置的属性,可以在布局中使用这些属性做初始化
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(); // 创建画笔
mPaint.setColor(mPaintColor); // 设置颜色
mPaint.setAntiAlias(true); // 抗锯齿
mPaint.setStrokeWidth(mStrokeWidth); // 设置描边宽度
mPaint.setStyle(Paint.Style.FILL); // 设置填充方式
paddingOne = mPadding; // 边距,这是柱体间的间距
paddingSecond = mPadding * 2;
paddingThird = mPadding * 3;
reset();
重置参数
private void reset() {
// 三个柱体开始高度(Y的开始坐标)这里设置的是3的倍数,这样绘制时就是递增递减
lineOneStartY = mHeight / 1.5f; // 第一根柱体开始的Y坐标
lineOneEndY = mHeight; // 第一根柱体结束的Y坐标
lineSecondStartY = mHeight / 3;
lineSecondEndY = mHeight;
lineThirdStartY = mHeight / 6;
lineThirdEndY = mHeight;
onePlus = true; // 第1根柱体高度值加减的标志
secondPlus = true; // 第2根柱体高度值加减的标志
thirdPlus = true; // 第3根柱体高度值加减的标志
}
开启线程不停的绘制
// 内部初始化时调用开始绘制或者可以设置在外部调用开启绘制
mThread = new Thread() {
@Override
public void run() {
while (true) {
if (running)
postInvalidate(); // 子线程中调用该方法就会不停的调用onDraw进行绘制 ,UI线程则调用invalidate()
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
mThread.start();
onDraw 关键方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!running) { // 停止时重置参数
reset();
}
// 绘制第一个柱体
canvas.drawLine(paddingOne, lineOneStartY, paddingOne, lineOneEndY, mPaint);
// 第二个
canvas.drawLine(paddingSecond, lineSecondStartY, paddingSecond, lineSecondEndY, mPaint);
// 第三个
canvas.drawLine(paddingThird, lineThirdStartY, paddingThird, lineThirdEndY, mPaint);
//========================================================
// 根据onePlus来设置Y坐标开始值的自增自减
if (onePlus) {
lineOneStartY++;
} else {
lineOneStartY--;
}
// 临界条件的判断
if (lineOneStartY >= mHeight) { // 当Y开始值自增>=指定的最大高度,此时Y开始值应该自减
onePlus = false;
} else if (lineOneStartY <= 0) { // 当Y开始值自减<=0时,此时Y开始值应该自增
onePlus = true;
}
//========================================================
// 第二个 ========================================================
if (secondPlus) {
lineSecondStartY++;
} else {
lineSecondStartY--;
}
if (lineSecondStartY >= mHeight) {
secondPlus = false;
} else if (lineSecondStartY <= 0) {
secondPlus = true;
}
// 第二个 ========================================================
// 第三个 ========================================================
if (thirdPlus) {
lineThirdStartY++;
} else {
lineThirdStartY--;
}
if (lineThirdStartY >= mHeight) {
thirdPlus = false;
} else if (lineThirdStartY <= 0) {
thirdPlus = true;
}
// 第三个 ========================================================
}
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,欢迎关注和star
网友评论