在做IM的需求中,难免要支持语音,那么肯定会有监听麦克风动态的改变话筒的音量的大小的view. 市面上大同小异都是仿微信的样子,而且实现方式也是序列帧动画.
这次根据效果图靠我们勤劳的双手来撸一个出来岂不是快哉…
1秒 ~ 2秒~ 3秒…来开撸.
- 先看效果图
浓浓的简约黑白风,ins风格…跑题了.我们这期就是要画上面那个话筒,和那个取消的回车键…
少啰嗦先看东西
接下来是取消状态的样子
大概就是这个样子,一只画笔就搞定了…(建议:如果赶工期,直接找设计切序列帧图,不敢工期也要找设计切图…?)
此时来一个GIF吧,但是清晰度就凑乎看吧,嫌不清晰的,把代码导入项目自己运行也行.
好了,到此结束了,谢谢观看…(?对了还没撸呢…那么开始吧)
流程如下
- 观察分析,抽取自定义属性
- 考虑适配的问题,根据效果图的尺寸计算所有用到的绘制rectF的约束比例
- 生成所有的绘制约束rectF
- 由于有话筒动态的变化,根据画笔PorterDuffXfermode 找合适的来进行绘制
- 自定义属性抽取(根据效果图和你的业务扩展)
<declare-styleable name="VchatAudioStateView">
<attr name="audioTextColor" format="color" />
<attr name="audioTextCancelColor" format="color" />
<attr name="audioTubeColor" format="color" />
<attr name="audioTextSize" format="dimension" />
<attr name="audioBackgroundColor" format="color" />
<attr name="audioCorners" format="dimension" />
<attr name="audioStrokeColor" format="color" />
<attr name="audioStrokeWidth" format="dimension" />
<attr name="audioTubeFillColor" format="color" />
<attr name="audioNormalDesc" format="string" />
<attr name="audioCancelDesc" format="string" />
<attr name="audioTubeLineWidth" format="dimension"/>
</declare-styleable>
- 计算约束比例
这个我是根据效果图的宽度当做基准比例为1,然后计算出我们要绘制的起点以及各个,绘制模块的坐标
比如我们先确定,画笔的下笔点,然后顺藤摸瓜,一次确定
/**
* 默认宽度(宽位比例基准)
* 高度为绘制基准(从底部小尾巴开始绘制)
*/
private static final float VIEW_DEF_WIDTH = 176.F;
/**
* 默认高度
*/
private static final float VIEW_DEF_HEIGHT = 145.F;
/**
* 话筒大碗的半径比例
*/
private static final float SCALE_OF_BIG_CIRCLE_RADIO = 60.F / 580;
/**
* 话筒小尾巴的宽度比例
*/
private static final float SCALE_OF_TAIL_WIDTH = 8.F / 580;
/**
* 话筒小尾巴的高度比例
*/
private static final float SCALE_OF_TAIL_HEIGHT = 20.F / 580;
/**
* 话筒的倒角比例
*/
private static final float SCALE_OF_TUBE_RECT_RADIO = 40.F / 580;
/**
* 话筒的高度比例
*/
private static final float SCALE_OF_TUBE_RECT_HEIGHT = 114.F / 580;
/**
* 话筒的宽度比例
*/
private static final float SCALE_OF_TUBE_RECT_WIDTH = 80.F / 580;
/**
* 开始绘制的y坐标比例
*/
private static final float SCALE_OF_AUDIO_START = 274.F / 580;
/**
* 话筒开始绘制的比例起点y坐标
*/
private static final float SCALE_OF_TUBE_RECT_START = 238.F / 580;
.......省略........
- 确定了要绘制的比例,第三步骤就是绘制了,
绘制的时候化繁为简,canvas能绘制基本图形,什么圆,弧形,矩形.还有....(其他的不重要,我也不会其他的,这三个完全能搞定这个话筒)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawStrokeBg(canvas);
drawFillBg(canvas);
if (cancelMode) {
drawTubeCancel(canvas);
drawAudioCancelDesc(canvas, audioCancelDesc);
} else {
drawTube(canvas);
drawAudioDesc(canvas, audioNormalDesc);
}
}
/**
* 绘制话筒填充
* 利用画布模式.来取交集
*
* @param canvas 画布
*/
private void drawTubeFillRect(Canvas canvas) {
audioTubePaint.setXfermode(xFermode);
audioTubePaint.setColor(audioTubeFillColor);
audioTubePaint.setStyle(Paint.Style.FILL);
canvas.drawRect(tubeFillRect, audioTubePaint);
audioTubePaint.setXfermode(null);
audioTubePaint.setColor(audioTubeColor);
audioTubePaint.setStyle(Paint.Style.STROKE);
}
/**
* 绘制话筒
*
* @param canvas 画布
*/
private void drawTubeRect(Canvas canvas) {
canvas.drawRoundRect(tubeRect, tubeRectRadio + tailWidth, tubeRectRadio, audioTubePaint);
}
/**
* 绘制话筒下面 大碗
*
* @param canvas 画布
*/
private void drawBigCircle(Canvas canvas) {
canvas.drawArc(bigCircleRectF, 0, 180, false, audioTubePaint);
}
/**
* 绘制小尾巴
*
* @param canvas 画布
*/
private void drawTail(Canvas canvas) {
canvas.drawRect(tailRectF, audioTailPaint);
}
上面就是绘制话筒的部分代码,我们把话筒分为静态部分和动态部分
静态部分就是那些黑色的框框,分别先绘制
1,小尾巴
2,大碗
3,话筒静态
4,动态背景
着重说下这个动态背景,这里我们就用到了画笔的X模式,那个经典的图,用
到的时候上网搜即可
这里我们用的模式是PorterDuff.Mode.MULTIPLY
我们让话筒里面灰色的矩形背景和静态的话筒相交,留下相交的部分,
把绘制的灰色矩形去掉不消交的角落即可.
经过上面的步骤就完成了话筒样式,解下来就是那个取消箭头的样式了,
这个似乎更简单了,这里只提一下,就是那个箭头的绘制
我们用path 先确定下箭头的点,然后往外面扩展两个点来定位箭头的开角度即可
代码虽然看着多,一共500多行吧,其实有300行是模板代码,还有100行注释吧,所以我们基本上可以用100行来实现这个话筒,下面就把完整的代码粘贴到下面.
/**
* 文件描述:再次建议一定要UI切图即使你会画?,因为各司其职,你切你的图,
* 用不用是我的事情?
*
* @author :feilong on 2018/10/22
*/
public class VchatAudioStateView extends View {
private PorterDuffXfermode xFermode = new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY);
/**
* 默认宽度(宽位比例基准)
* 高度为绘制基准(从底部小尾巴开始绘制)
*/
private static final float VIEW_DEF_WIDTH = 176.F;
/**
* 默认高度
*/
private static final float VIEW_DEF_HEIGHT = 145.F;
/**
* 话筒大碗的半径比例
*/
private static final float SCALE_OF_BIG_CIRCLE_RADIO = 60.F / 580;
/**
* 话筒小尾巴的宽度比例
*/
private static final float SCALE_OF_TAIL_WIDTH = 8.F / 580;
/**
* 话筒小尾巴的高度比例
*/
private static final float SCALE_OF_TAIL_HEIGHT = 20.F / 580;
/**
* 话筒的倒角比例
*/
private static final float SCALE_OF_TUBE_RECT_RADIO = 40.F / 580;
/**
* 话筒的高度比例
*/
private static final float SCALE_OF_TUBE_RECT_HEIGHT = 114.F / 580;
/**
* 话筒的宽度比例
*/
private static final float SCALE_OF_TUBE_RECT_WIDTH = 80.F / 580;
/**
* 开始绘制的y坐标比例
*/
private static final float SCALE_OF_AUDIO_START = 274.F / 580;
/**
* 话筒开始绘制的比例起点y坐标
*/
private static final float SCALE_OF_TUBE_RECT_START = 238.F / 580;
/**
* 文字开始绘制的y坐标比例
*/
private static final float SCALE_OF_DESC_START = 370.F / 580;
/**
* 取消箭头的总高度 40.F / 140 (高度比例基准dp)
*/
private static final float SCALE_OF_CANCEL_HEIGHT = 40.F / 140;
/**
* 取消箭头的总宽度比例
*/
private static final float SCALE_OF_CANCEL_WIDTH = 24.F / 140;
private float bigCircleRadio;
private float tailWidth;
private float tailHeight;
private float tubeRectRadio;
private float tubeRectHeight;
private float tubeRectWidth;
private float cancelTotalHeight;
private float cancelTotalWidth;
/**
* 高度为基准,开始绘制的小尾巴中间点坐标
*/
private AudioPoint startPoint;
private AudioPoint audioTextPoint;
private AudioPoint tuebRectStartPoint;
private int audioTextColor;
private int audioTextSize;
private int audioBackgroundColor;
private int audioCorners;
private int audioStrokeColor;
private int audioStrokeWidth;
private int audioTubeFillColor;
private int audioTextCancelColor;
private int audioTubeColor;
private int audioViewHeight;
private int audioViewWidth;
private int audioTubeLineWidth;
private Paint audioFillPaint;
private Paint audioTextPaint;
private Paint audioTextCancelPaint;
private Paint audioStrokePaint;
private Paint audioTubePaint;
private Paint audioTubeFillPaint;
private Paint audioTailPaint;
private RectF fillRoundRect;
private RectF strokeRoundRect;
private RectF tailRectF;
private RectF bigCircleRectF;
private RectF tubeRect;
private RectF tubeFillRect;
private RectF cancelLeftRectF;
private RectF cancelArcRectF;
private RectF cancelRightRectF;
private Path arrowPath;
private String audioNormalDesc;
private String audioCancelDesc;
/**
* 绘制的模式取消或者正常
*/
private boolean cancelMode;
/**
* 音量输入的大小转变成距离
*/
private float volumeHeight;
/**
* 最大音量的高度
*/
private float volumeMaxHeight;
private float tubeFillTop;
public VchatAudioStateView(Context context) {
this(context, null);
}
public VchatAudioStateView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VchatAudioStateView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs, defStyleAttr);
setBackgroundColor(audioBackgroundColor);
initPaints();
}
/**
* 初始化画笔
*/
private void initPaints() {
audioTextPaint = creatPaint(audioTextColor, audioTextSize, Paint.Style.FILL, 0);
audioTextCancelPaint = creatPaint(audioTextCancelColor, audioTextSize, Paint.Style.FILL, 0);
audioStrokePaint = creatPaint(audioStrokeColor, 0, Paint.Style.FILL, 0);
audioTubePaint = creatTubePaint(audioTubeColor, 0, Paint.Style.STROKE, 0);
audioTubeFillPaint = creatPaint(audioTubeFillColor, 0, Paint.Style.FILL, 0);
audioFillPaint = creatPaint(audioBackgroundColor, 0, Paint.Style.FILL, 0);
audioTailPaint = creatTubePaint(audioTubeColor, 0, Paint.Style.FILL, 0);
}
/**
* 初始化自定义属性
*
* @param context 上线文
* @param attrs 属性
* @param defStyleAttr 默认style
*/
private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VchatAudioStateView, defStyleAttr, R.style.DefaultVchatAudioStateStyle);
int count = typedArray.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.VchatAudioStateView_audioTextColor:
audioTextColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioTextSize:
audioTextSize = typedArray.getDimensionPixelSize(attr, 0);
break;
case R.styleable.VchatAudioStateView_audioBackgroundColor:
audioBackgroundColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioCorners:
audioCorners = typedArray.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.VchatAudioStateView_audioStrokeColor:
audioStrokeColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioStrokeWidth:
audioStrokeWidth = typedArray.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.VchatAudioStateView_audioTubeFillColor:
audioTubeFillColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioTubeColor:
audioTubeColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioTextCancelColor:
audioTextCancelColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioTubeLineWidth:
audioTubeLineWidth = typedArray.getDimensionPixelOffset(attr, Color.BLACK);
break;
case R.styleable.VchatAudioStateView_audioNormalDesc:
audioNormalDesc = typedArray.getString(attr);
break;
case R.styleable.VchatAudioStateView_audioCancelDesc:
audioCancelDesc = typedArray.getString(attr);
break;
default:
break;
}
}
typedArray.recycle();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
audioViewHeight = h;
audioViewWidth = w;
bigCircleRadio = w * SCALE_OF_BIG_CIRCLE_RADIO;
tailWidth = w * SCALE_OF_TAIL_WIDTH;
tailHeight = w * SCALE_OF_TAIL_HEIGHT;
tubeRectRadio = w * SCALE_OF_TUBE_RECT_RADIO;
tubeRectWidth = w * SCALE_OF_TUBE_RECT_WIDTH;
tubeRectHeight = w * SCALE_OF_TUBE_RECT_HEIGHT;
cancelTotalHeight = h * SCALE_OF_CANCEL_HEIGHT;
cancelTotalWidth = h * SCALE_OF_CANCEL_WIDTH;
startPoint = new AudioPoint(w * 0.5F, w * SCALE_OF_AUDIO_START);
audioTextPoint = new AudioPoint(w * 0.5F, w * SCALE_OF_DESC_START);
tuebRectStartPoint = new AudioPoint(w * 0.5F, w * SCALE_OF_TUBE_RECT_START);
// 给画笔设定宽度
audioTubePaint.setStrokeWidth(tailWidth);
audioTubeFillPaint.setXfermode(xFermode);
strokeRoundRect = new RectF(0, 0, audioViewWidth, audioViewHeight);
fillRoundRect = new RectF(audioStrokeWidth, audioStrokeWidth, audioViewWidth - audioStrokeWidth, audioViewHeight - audioStrokeWidth);
float tailLeft = audioViewWidth * 0.5F - tailWidth * 0.5F;
float tailTop = startPoint.y - tailHeight;
float tailRight = audioViewWidth * 0.5F + tailWidth * 0.5F;
float tailBottom = startPoint.y;
tailRectF = new RectF(tailLeft, tailTop, tailRight, tailBottom);
//组装外面的大碗
float bigCircleLeft = audioViewWidth * 0.5F - bigCircleRadio;
float bigCircleRight = audioViewWidth * 0.5F + bigCircleRadio;
float bigCircleBottom = tailRectF.top;
float bigCircleTop = bigCircleBottom - bigCircleRadio * 2;
bigCircleRectF = new RectF(bigCircleLeft, bigCircleTop, bigCircleRight, bigCircleBottom);
// 组装话筒的圆角矩形
float tubeLeft = audioViewWidth * 0.5F - tubeRectWidth * 0.5F;
float tubeRight = audioViewWidth * 0.5F + tubeRectWidth * 0.5F;
float tubeBottom = tuebRectStartPoint.y;
float tubeTop = tubeBottom - tubeRectHeight;
tubeRect = new RectF(tubeLeft, tubeTop, tubeRight, tubeBottom);
// 记录最大音量的距离
volumeMaxHeight = tubeRect.bottom - tubeRect.top;
// 组装话筒中根据语音音量大小要改变的灰色填充北京,其中要改变的是矩形的高度范围
float tubeFillLeft = tubeLeft + tailWidth * 0.5F;
float tubeFillRight = tubeRight - tailWidth * 0.5F;
float tubeFillBottom = tubeBottom - tailWidth * 0.5F;
tubeFillTop = (tubeTop + tailWidth * 0.5F) + volumeHeight;
tubeFillRect = new RectF(tubeFillLeft, tubeFillTop, tubeFillRight, tubeFillBottom);
// 组装取消模式左边的矩形区域
float cancelLeft = audioViewWidth * 0.5F - cancelTotalWidth * 0.5F;
float cancelRight = cancelLeft + tailWidth * 1.F;
float cancelBottom = audioViewHeight * 0.5F;
float cancelTop = cancelBottom - cancelTotalHeight + tubeRectRadio;
cancelLeftRectF = new RectF(cancelLeft, cancelTop, cancelRight, cancelBottom);
// 组织取消模式上面的弧形区域
float cancelArcLeft = cancelLeftRectF.left + tailWidth * 0.5F;
float cancelArcTop = audioViewHeight * 0.5F - cancelTotalHeight;
float cancelArcRight = cancelArcLeft + tubeRectRadio * 2 + tailWidth * 0.5F;
float cancelArcBottom = cancelArcTop + tubeRectRadio * 2;
cancelArcRectF = new RectF(cancelArcLeft, cancelArcTop, cancelArcRight, cancelArcBottom);
// 组装取消模式右边的矩形区域
float cancelRightLeft = cancelArcRectF.right - tailWidth * 0.5F;
float cancelRightTop = cancelLeftRectF.top;
float cancelRightRight = cancelRightLeft + tailWidth;
float cancelRightBottom = cancelLeftRectF.bottom - 0.5F * (cancelLeftRectF.bottom - cancelLeftRectF.top);
cancelRightRectF = new RectF(cancelRightLeft, cancelRightTop, cancelRightRight, cancelRightBottom);
// 组装箭头数据
float arrowTopX = cancelRightRectF.left + tailWidth * 0.5F;
float arrowTopY = cancelRightRectF.bottom + tailWidth * 0.5F;
float cons = 2.5F;
float startX = arrowTopX - tailWidth * cons;
float startY = arrowTopY - tailWidth * cons;
float endX = arrowTopX + tailWidth * cons;
float endY = arrowTopY - tailWidth * cons;
arrowPath = new Path();
arrowPath.moveTo(startX, startY);
arrowPath.lineTo(arrowTopX, arrowTopY);
arrowPath.lineTo(endX, endY);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMeasure = 0;
int heightMeasure = 0;
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
widthMeasure = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, VIEW_DEF_WIDTH, getContext().getResources().getDisplayMetrics());
widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthMeasure, MeasureSpec.EXACTLY);
}
if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
heightMeasure = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, VIEW_DEF_HEIGHT, getResources().getDisplayMetrics());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasure, MeasureSpec.EXACTLY);
}
int viewMeasureSpec = widthMeasure - heightMeasure >= 0 ? heightMeasureSpec : widthMeasureSpec;
super.onMeasure(viewMeasureSpec, viewMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawStrokeBg(canvas);
drawFillBg(canvas);
if (cancelMode) {
drawTubeCancel(canvas);
drawAudioCancelDesc(canvas, audioCancelDesc);
} else {
drawTube(canvas);
drawAudioDesc(canvas, audioNormalDesc);
}
}
/**
* 创建画笔
*
* @return 画笔
*/
private Paint creatPaint(int paintColor, int textSize, Paint.Style style, int lineWidth) {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(lineWidth);
paint.setDither(true);
paint.setTextSize(textSize);
paint.setStyle(style);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
return paint;
}
private Paint creatTubePaint(int paintColor, int textSize, Paint.Style style, int lineWidth) {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(lineWidth);
paint.setDither(true);
paint.setTextSize(textSize);
paint.setStyle(style);
return paint;
}
/**
* 绘制描述文案
*
* @param canvas 画不
* @param audioDesc 文案描述
*/
private void drawAudioDesc(Canvas canvas, String audioDesc) {
AudioPoint audioPoint = measureTextSize(audioTextPaint, audioDesc);
float textY = audioTextPoint.y + audioPoint.y;
float textX = audioViewWidth * 0.5F - audioPoint.x * 0.5F;
canvas.drawText(audioDesc, textX, textY, audioTextPaint);
}
private void drawAudioCancelDesc(Canvas canvas, String audioDesc) {
AudioPoint audioPoint = measureTextSize(audioTextCancelPaint, audioDesc);
float textY = audioTextPoint.y + audioPoint.y;
float textX = audioViewWidth * 0.5F - audioPoint.x * 0.5F;
canvas.drawText(audioDesc, textX, textY, audioTextCancelPaint);
}
/**
* 绘制取消的图案
*
* @param canvas 画布
*/
private void drawTubeCancel(Canvas canvas) {
drawCancelLeftRect(canvas);
drawCancelArc(canvas);
drawCancelRightRect(canvas);
drawCancelArrowPath(canvas);
}
/**
* 绘制箭头
*
* @param canvas 画布
*/
private void drawCancelArrowPath(Canvas canvas) {
audioTailPaint.setStyle(Paint.Style.STROKE);
audioTailPaint.setStrokeWidth(tailWidth);
canvas.drawPath(arrowPath, audioTailPaint);
audioTailPaint.setStrokeWidth(0);
audioTailPaint.setStyle(Paint.Style.FILL);
}
/**
* 绘制取消录音右边的矩形
*
* @param canvas 画布
*/
private void drawCancelRightRect(Canvas canvas) {
canvas.drawRect(cancelRightRectF, audioTailPaint);
}
/**
* 绘制取消录音上面的半圆
*
* @param canvas 画布
*/
private void drawCancelArc(Canvas canvas) {
audioTailPaint.setStyle(Paint.Style.STROKE);
audioTailPaint.setStrokeWidth(tailWidth);
canvas.drawArc(cancelArcRectF, -180, 180, false, audioTailPaint);
audioTailPaint.setStrokeWidth(0);
audioTailPaint.setStyle(Paint.Style.FILL);
}
/**
* 绘制取消录音左边的矩形
*
* @param canvas 画布
*/
private void drawCancelLeftRect(Canvas canvas) {
canvas.drawRect(cancelLeftRectF, audioTailPaint);
}
/**
* 绘制话筒
*
* @param canvas 画布
*/
private void drawTube(Canvas canvas) {
drawTail(canvas);
drawBigCircle(canvas);
drawTubeRect(canvas);
drawTubeFillRect(canvas);
}
/**
* 绘制话筒填充
* 利用画布模式.来取交集
*
* @param canvas 画布
*/
private void drawTubeFillRect(Canvas canvas) {
audioTubePaint.setXfermode(xFermode);
audioTubePaint.setColor(audioTubeFillColor);
audioTubePaint.setStyle(Paint.Style.FILL);
canvas.drawRect(tubeFillRect, audioTubePaint);
audioTubePaint.setXfermode(null);
audioTubePaint.setColor(audioTubeColor);
audioTubePaint.setStyle(Paint.Style.STROKE);
}
/**
* 绘制话筒
*
* @param canvas 画布
*/
private void drawTubeRect(Canvas canvas) {
canvas.drawRoundRect(tubeRect, tubeRectRadio + tailWidth, tubeRectRadio, audioTubePaint);
}
/**
* 绘制话筒下面 大碗
*
* @param canvas 画布
*/
private void drawBigCircle(Canvas canvas) {
canvas.drawArc(bigCircleRectF, 0, 180, false, audioTubePaint);
}
/**
* 绘制小尾巴
*
* @param canvas 画布
*/
private void drawTail(Canvas canvas) {
canvas.drawRect(tailRectF, audioTailPaint);
}
/**
* 绘制话筒填充色
*
* @param canvas 画布
*/
private void drawFillBg(Canvas canvas) {
canvas.drawRoundRect(fillRoundRect, audioCorners, audioCorners, audioFillPaint);
}
/**
* 绘制描边背景
*
* @param canvas 画布
*/
private void drawStrokeBg(Canvas canvas) {
canvas.drawRoundRect(strokeRoundRect, audioCorners, audioCorners, audioStrokePaint);
}
/**
* 坐标对象
*/
class AudioPoint {
public float x;
public float y;
AudioPoint() {
}
AudioPoint(float x, float y) {
this.x = x;
this.y = y;
}
}
/**
* 返回文字的宽和高,x代表宽,y代表高度
*
* @param textPaint 画笔
* @param text 文字
* @return 文字的宽和高
*/
private AudioPoint measureTextSize(Paint textPaint, String text) {
AudioPoint point = new AudioPoint();
if (!TextUtils.isEmpty(text)) {
point.x = textPaint.measureText(text);
Paint.FontMetrics fm = textPaint.getFontMetrics();
point.y = (float) Math.ceil(fm.descent - fm.top);
}
return point;
}
/**
* 设置绘制的模式,是否为取消模式
*
* @param cancelMode 模式
*/
public void setCancelMode(boolean cancelMode) {
this.cancelMode = cancelMode;
invalidate();
}
/**
* 音量大小百分比
*
* @param percent 百分比
*/
public void updateVolume(float percent) {
volumeHeight = volumeMaxHeight - volumeMaxHeight * percent;
tubeFillRect.top = tubeFillTop + volumeHeight;
invalidate();
}
public void setAudioNormalDesc(String audioNormalDesc) {
this.audioNormalDesc = audioNormalDesc;
invalidate();
}
public void setAudioCancelDesc(String audioCancelDesc) {
this.audioCancelDesc = audioCancelDesc;
}
}
能坚持到最后说明你耐力真的 可以啊,撸完了,到此结束,荆轲刺秦王…(怀念了可惜节目停播了)