安卓自定义View之进度麦克风

安卓自定义View之进度麦克风

前言

工作需要一个能显示进度的麦克风,即要体现出现在的声音分贝是变化的,所以设计一个带双层贝塞尔曲线的麦克风;


在哪个位置来展现现在声音分贝是变化的呢?思来想去,就用麦克风上面的圆角矩形区域,通过改变一个路径(path)的纵坐标,再画贝塞尔曲线是可以实现的,说干就干!

一、效果图

进度43

进度0

麦克风进度变化效果

二、自定义属性

先在项目的 \src\main\res\values 路径下新建一个attrs.xml 文件,如果已经存在则直接打开;

新建一个declare-styleable 标签,名字就叫MicView

首先需要画一个麦克风,所以可以先定义 画麦克风 的 画笔颜色和粗细:

<declare-styleable name="MicView">
        <!-- 麦克风画笔的颜色-->
        <attr name="mic_view_paint_color" format="reference|color" />
        <!-- 麦克风画笔的粗细-->
        <attr name="mic_view_paint_stroke_width" format="reference|float" />
    </declare-styleable>

为了让头部矩形区域的颜色可以单独控制,所以给头部矩形区域的画笔 也定义颜色和粗细:

<declare-styleable name="MicView">
        <!-- 省略代码-->
        <!-- 麦克风头部矩形区域画笔的颜色-->
        <attr name="mic_view_round_rect_paint_color" format="reference|color" />
        <!-- 麦克风头部矩形区域画笔的粗细-->
        <attr name="mic_view_round_rect_paint_stroke_width" format="reference|float" />
    </declare-styleable>

接下来还要能控制头部矩形区域的圆角到底有圆,所以也定义圆角半径x和y;

波浪的宽高;

第一条波浪的颜色,粗细;
第二条波浪的颜色,粗细;
是否显示第二条波浪?
现在的进度?即曲线的高度占头部矩形区域的百分比是多少?
还要显示文字,比如 50%;
文字颜色,尺寸;

这些都定义好属性,这样方便在xml设计时,随时更改参数来看预览效果;

不断的调整,最终用得较多的属性定义如下:

<declare-styleable name="MicView">
 		<!-- 麦克风画笔的颜色-->
        <attr name="mic_view_paint_color" format="reference|color" />
        <!-- 麦克风画笔的粗细-->
        <attr name="mic_view_paint_stroke_width" format="reference|float" />
        <!-- 麦克风头部矩形区域画笔的颜色-->
        <attr name="mic_view_round_rect_paint_color" format="reference|color" />
        <!-- 麦克风头部矩形区域画笔的粗细-->
        <attr name="mic_view_round_rect_paint_stroke_width" format="reference|float" />
        <!-- 麦克风头部矩形圆角半径x-->
        <attr name="mic_view_round_rect_corner_radius_x" format="reference|float" />
        <!-- 麦克风头部矩形圆角半径y-->
        <attr name="mic_view_round_rect_corner_radius_y" format="reference|float" />
        <!-- 波浪的宽度-->
        <attr name="mic_view_wave_width" format="reference|dimension" />
        <!-- 波浪的高度-->
        <attr name="mic_view_wave_height" format="reference|dimension" />
        <!-- 第一条曲线画笔的颜色-->
        <attr name="mic_view_wave_paint_color" format="reference|color" />
        <!-- 第一条曲线画笔的粗细-->
        <attr name="mic_view_wave_paint_stroke_width" format="reference|float" />
        <!-- 是否绘制第二条曲线-->
        <attr name="mic_view_is_show_second_wave" format="reference|boolean" />
        <!-- 第二条曲线的颜色-->
        <attr name="mic_view_second_wave_paint_color" format="reference|color" />
        <!-- 第二条曲线画笔的粗细-->
        <attr name="mic_view_second_wave_paint_stroke_width" format="reference|float" />
        <!-- 进度-->
        <attr name="mic_view_progress_mic" format="reference|integer" />
        <!-- 文字画笔的颜色-->
        <attr name="mic_view_text_paint_color" format="reference|color" />
        <!-- 文字内容-->
        <attr name="mic_view_text_str" format="reference|string" />
        <!-- 文字尺寸-->
        <attr name="mic_view_text_size" format="reference|integer|float" />
        <!-- 动画的更新间隔  快慢-->
        <attr name="mic_view_anim_interval" format="reference|integer" />
    </declare-styleable>

三、关键设计

1.新建MicView继承View

1.1新增必要的构造函数

package com.linkpoon.mixed.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class MicView extends View {
   

    public MicView(Context context) {
   
        this(context, null);
    }

    public MicView(Context context, @Nullable AttributeSet attrs) {
   
        this(context, attrs, 0);
    }

    public MicView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
   
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

}

1.2读取自定义属性并初始化

    private RectF roundRectF; /*麦克风上部的圆角矩形区域*/
    private float cornerRadiusX = 150;// 圆角矩形的 圆角半径
    private float cornerRadiusY = 150;// 圆角矩形的 圆角半径
    private RectF arcRectF; /*麦克风外围的U形区域*/
    private Paint roundPaint; /*麦克风上部的圆角矩形画笔*/
    private Paint micPaint;   /*麦克风画笔*/

    private Path roundPath;/*麦克风上部的圆角矩形路径*/

    private int defaultSize = 200;//自定义View默认的宽高

    /*波浪曲线画笔*/
    private Paint wavePaint;
    /*波浪曲线的路径*/
    private Path wavePath;
    private float waveWidth;//波浪宽度
    private float waveHeight;//波浪高度
    private int waveNum;//波浪组的数量(一次起伏为一组)
    private float waveMovingDistance;//波浪平移的距离

    /*第二层波浪曲线画笔*/
    private Paint secondWavePaint;
    private Path secondWavePath;// 第二层波浪路径

    private boolean showSecondWave;//是否绘制第二层波浪

    /*文本画笔*/
    private Paint textPaint;
    /*要显示的文字*/
    private String textStr;


    /*当前进度*/
    private int progress = 0;
    public static final int MAX_PROGRESS = 100;//先不考虑可以动态设置 进度最大值的问题,默认最大值为 100
    public static final int MIN_PROGRESS = 0;//先不考虑可以动态设置 进度最小值的问题,默认最小值为 0


    /*是否正在动画*/
    private boolean isAnimating = false;

    private double steep = 0;

    private final Random random = new Random();

    public String getTextStr() {
   
        return textStr;
    }

    public void setTextStr(String textStr) {
   
        if (textStr == null) {
   
            textStr = "";
        }
        this.textStr = textStr;
    }

    public boolean isShowSecondWave() {
   
        return showSecondWave;
    }

    public void setShowSecondWave(boolean showSecondWave) {
   
        this.showSecondWave = showSecondWave;
        invalidate();
    }

    public void setAnimating(boolean animating) {
   
        isAnimating = animating;
    }

    public boolean isAnimating() {
   
        return isAnimating;
    }

    
    /**
     * 将 dp 转换成 px
     */
    private int dipToPx(float dip) {
   
        float density = getResources().getDisplayMetrics().density;
        return (int) ((dip * density) + 0.5f);
    }

    private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
   
        roundPath = new Path();
        arcRectF = new RectF();
        roundRectF = new RectF();

        try (TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MicView)) {
   
			//波浪的宽度
            waveWidth = typedArray.getDimension(R.styleable.MicView_mic_view_wave_width, dipToPx(25));
            //波浪的高度
            waveHeight = typedArray.getDimension(R.styleable.MicView_mic_view_wave_height, dipToPx(5));

            //240 255 255	#F0FFFF 灰白色
            int roundPaintColorDefault = Color.argb(255, 240, 255, 255);
            int roundPaintColor = typedArray.getColor(R.styleable.MicView_mic_view_round_rect_paint_color, roundPaintColorDefault);
            float roundStrokeWidth = typedArray.getFloat(R.styleable.MicView_mic_view_round_rect_paint_stroke_width, dipToPx(1));
            roundPaint = new Paint();
            roundPaint.setAntiAlias(true);
            roundPaint.setColor(roundPaintColor);
            roundPaint.setStrokeWidth(roundStrokeWidth);
            roundPaint.setStyle(Paint.Style.FILL);

            cornerRadiusX = typedArray.getFloat(R.styleable.MicView_mic_view_round_rect_corner_radius_x, 150);
            cornerRadiusY = typedArray.getFloat(R.styleable.MicView_mic_view_round_rect_corner_radius_y, 150);


            //176 224 230	#B0E0E6  力量蓝
            int micPaintColorDefault = Color.argb(255, 176, 224, 230);
            int micPaintColor = typedArray.getColor(R.styleable.MicView_mic_view_paint_color, micPaintColorDefault);
            float micStrokeWidth = typedArray.getFloat(R.styleable.MicView_mic_view_paint_stroke_width, dipToPx(5));
            micPaint = new Paint();
            micPaint.setAntiAlias(true);
            micPaint.setColor(micPaintColor);
            micPaint.setStrokeWidth(micStrokeWidth);
            micPaint.setStyle(Paint.Style.STROKE);

            int wavePaintColorDefault = getResources().getColor(R.color.colorPrimaryHalf);
            int wavePaintColor = typedArray.getColor(R.styleable.MicView_mic_view_wave_paint_color, wavePaintColorDefault);
            float waveStrokeWidth = typedArray.getFloat(R.styleable.MicView_mic_view_wave_paint_stroke_width, dipToPx(5));
            wavePath = new Path();
            wavePaint = new Paint();
            wavePaint.setAntiAlias(true);
            wavePaint.setColor(wavePaintColor);
            wavePaint.setStrokeWidth(waveStrokeWidth);
            wavePaint.setStyle(Paint.Style.FILL);

            //154 255 154	#9AFF9A 绿色
            int secondWavePaintColorDefault = Color.argb(255, 154, 255, 154);
            int secondWaveColor = typedArray.getColor(R.styleable.MicView_mic_view_second_wave_paint_color, secondWavePaintColorDefault);
            float secondWaveStrokeWidth = typedArray.getFloat(R.styleable.MicView_mic_view_second_wave_paint_stroke_width, dipToPx(5));
            secondWavePath = new Path();
            secondWavePaint = new Paint();
            secondWavePaint.setAntiAlias(true);
            secondWavePaint.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值