做过的自定义 View
做过的自定义 View
音频条状图
需求
-
最终效果类似于音频图中的条状图
-
只是效果模拟,并不监听真实的音频
-
条的宽度相同,高度随机;条的颜色是红到黄的线性渐变
-
随着时间的变化,条的高度发生变化
详细设计
-
自定义属性
-
条的宽度(默认 3dp)
-
条的颜色变化范围(两个颜色——默认红色、橙色)
-
条之间的间距
-
整个 View 的背景颜色
-
变化的频率,单位是毫秒
-
-
处理起始绘制的坐标,并结合条间距计算 View 能显示多少个条。计算方法:条的总数 = (View 的宽度 - 条间距 * 2) / (条的宽度 + 条间距)
-
随机生成条的高度,高度的范围:[1, 控件的高度]
-
条的颜色在两个颜色之间,随时间呈线性梯度变化
具体实现
-
定义自定义属性(res/values/attrs.xml):
<declare-styleable name="AudioBarChart"> <attr name="barWidth" format="reference|dimension" /><!-- 条的宽度,默认 3dp --> <attr name="barStartColor" format="reference|color" /><!-- 条颜色的起始值,默认红色 --> <attr name="barEndColor" format="reference|color" /><!-- 条颜色的结束值,默认橙色 --> <attr name="barSpace" format="reference|dimension" /><!-- 条间距,默认 1dp --> <attr name="wholeBgColor" format="reference|color" /><!-- 整个的背影颜色,默认白色 --> <attr name="changeFrenquency" format="integer" /><!-- 条变化的频率,单位毫秒,默认 300 --> </declare-styleable>
-
获取自定义属性并指定默认值:
public AudioBarChart(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AudioBarChart); mBarWidth = (int) typedArray.getDimension(R.styleable.AudioBarChart_barWidth, 20); mBarStartColor = typedArray.getColor(R.styleable.AudioBarChart_barStartColor, getResources().getColor(R.color.audio_bar_chart_red)); mBarEndColor = typedArray.getColor(R.styleable.AudioBarChart_barEndColor, getResources().getColor(R.color.audio_bar_chart_orange)); mBarSpace = (int) typedArray.getDimension(R.styleable.AudioBarChart_barSpace, 5); mWholeBgColor = typedArray.getColor(R.styleable.AudioBarChart_wholeBgColor, getResources().getColor(android.R.color.white)); mChangeFrequency = typedArray.getInt(R.styleable.AudioBarChart_changeFrenquency, 300); typedArray.recycle(); }
-
测量并初始化变量值:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(mWidth, mHeight); mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBarPaint.setStyle(Paint.Style.FILL); mBarCount = (mWidth - mBarSpace * 2) / (mBarWidth + mBarSpace); }
-
绘制:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); setBackgroundColor(mWholeBgColor); for (int i = 0; i < mBarCount; i++) { int height = mHeight - new Random().nextInt(mHeight * 3 / 4); int x = (i + 1) * mBarSpace + i * mBarWidth; Rect rect = new Rect(x, height, x + mBarWidth, mHeight); mLinearGradient = new LinearGradient(x, mHeight, x + mBarWidth, height, mBarStartColor, mBarEndColor, Shader.TileMode.CLAMP); mBarPaint.setShader(mLinearGradient); canvas.drawRect(rect, mBarPaint); } postInvalidateDelayed(mChangeFrequency); }
-
最终效果: