Android 自定义音量控件

声明:
本文借鉴鸿洋大神博客:
http://blog.csdn.net/lmj623565791/article/details/24529807

首先来看下效果图:

首先来分析下这个控件的组成:
1.音量图标
2.弧形的线

音量图标可以之间使用canvas.drawBitmap方法直接绘制上去
弧线绘制也可以使用canvas.drawArc来绘制,这里我们要对画笔进行一些是设置,在下面会详细讲解:

1.首先来重写一些所必要的方法

package wkk.dome4;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2016/5/15.
 */
public class RoundView extends View {

    //画笔
    private Paint paint;
    //画笔的粗细,即圆环的宽度
    private int thickness = 13;
    //音量的总个数
    private int size = 12;
    //音量的大小
    private int istrue = 10;
    //音量间的间距
    private int distance = 15;

    //1.构造方法,一般用来初始化相关变量,以及得到所自定义的属性
    public RoundView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint=new Paint();
    }

    //2.对控件的大小进行设置
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    //3.主要用来绘图的方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    //4.处理与用户的交互
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
}

一般来说重写的有以上几个方法,但是并非所有的方法都要重写,根据自己的需要去重写

2.重写onMeasure
首先我们来看一下啊没有重写时的效果


    //3.主要用来绘图的方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.BLUE);
        //绘制矩形,参数分别为left,top,rightt,tottom,paint
        canvas.drawRect(0,0,getWidth(),getHeight(),paint);
    }

    <wkk.dome1.RoundView
        android:layout_width="200dp"
        android:layout_height="200dp" />

此时的效果是这样的

看起来很正常,我们来将宽和高改成wrap_content之后来看看效果:


好吧,这并不是我想要的效果,想要不是这样的效果我们来重写onMeasure方法以控制控件的大小:

    //2.对控件的大小进行设置
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //得到控件的宽高以及模式
        int widthSize=MeasureSpec.getSize(widthMeasureSpec);
        int widthMode=MeasureSpec.getMode(widthMeasureSpec);

        int heightSize=MeasureSpec.getSize(heightMeasureSpec);
        int heightMode=MeasureSpec.getMode(heightMeasureSpec);

        int width=0;
        int height=0;

        //widthMode 即是宽度的模式 即用来判断宽度是wrap_content还是match_parent
        //MeasureSpec.EXACTLY代表的是match_parent以及具体的数值例如200dp
        if(widthMode!= MeasureSpec.EXACTLY&&heightMode!= MeasureSpec.EXACTLY){
            //此方法通知View修改控件宽高
            setMeasuredDimension(width, height);
        } else {
            //如果宽高中有一个是定义的具体数值,我们去最小值
            width = Math.min(widthSize, heightSize);
            setMeasuredDimension(width, width);
        }

    }

3.重写最重要的onDraw方法

    //3.主要用来绘图的方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //对画笔进行设置
        //防抖动
        paint.setDither(true);
        //防锯齿
        paint.setAntiAlias(true);
        //设置画笔的宽度
        paint.setStrokeWidth(thickness);
        //画笔颜色
        paint.setColor(Color.WHITE);
        //设置样式为空心
        paint.setStyle(Paint.Style.STROKE);
        //定义线段形状-设置了这个之后 线段的开头和结尾都会变得有弧度
        paint.setStrokeCap(Paint.Cap.ROUND);

        //得到圆心的x轴坐标
        int a = getWidth() / 2;
        //因为绘制的圆环是以画笔的宽度来决定内院和外圆的距离的所以要/2
        int b = a - thickness / 2;
        //参数为矩形的四个点的坐标
        RectF f = new RectF(a - b, a - b, a + b, a + b);
        //绘制圆弧 参数为 矩形 起始位置 结束距离 画笔
        canvas.drawArc(f, -180, 10, false, paint);
    }

看下效果:

现在线段就有了,我们只需要通过循环去绘制每一个音量就行了

    //3.主要用来绘图的方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //对画笔进行设置
        //防抖动
        paint.setDither(true);
        //防锯齿
        paint.setAntiAlias(true);
        //设置画笔的宽度
        paint.setStrokeWidth(thickness);
        //画笔颜色
        paint.setColor(Color.WHITE);
        //设置样式为空心
        paint.setStyle(Paint.Style.STROKE);
        //定义线段形状-设置了这个之后 线段的开头和结尾都会变得有弧度
        paint.setStrokeCap(Paint.Cap.ROUND);

        //得到圆心的x轴坐标
        int a = getWidth() / 2;
        //因为绘制的圆环是以画笔的宽度来决定内院和外圆的距离的所以要/2
        int b = a - thickness / 2;
        //参数为矩形的四个点的坐标
        RectF f = new RectF(a - b, a - b, a + b, a + b);

        //总弧度
        int z = 250;
        //每一个音量所占据的弧度
        int one = (z - ((size - 1) * distance)) / size;
        //圆弧的起始位置
        int s = -180 - (z - 180) / 2;
        //绘制选中
        for (int i = 1; i <= istrue; i++) {
            //绘制圆弧 参数为 矩形 起始位置 结束距离 画笔
            canvas.drawArc(f, s, one, false, paint);
            s = s + one + distance;
        }
        paint.setColor(0xaa25221C);
        //绘制未选中
        for (int i = 1; i <= size - istrue; i++) {
            canvas.drawArc(f, s, one, false, paint);
            s = s + one + distance;
        }
    }

看下效果:

怎么样,基本上和我们所需要的效果相差无几了,接下来绘制音量图标,这个就简单了:
在onDraw方法中继续添加代码:

        //绘制图标
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_a);
        int c = (getWidth() - bitmap.getWidth()) / 2;
        //参数为所需要绘制的bitmap 左边位置 顶部位置 画笔
        canvas.drawBitmap(bitmap, c, c, paint);

效果如图:

4.重写:onTouchEvent
处理响应用户点击,并提供向外部提供方法

    //4.处理与用户的交互
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_UP) {
            float x = event.getX();
            if (x > getRight() / 2) {
                jian();
            } else {
                jia();
            }
        }
        return true;
    }


    //加
    public void jia() {
        if (istrue < size) {
            istrue += 1;
            invalidate();
        }
    }
    //减
    public void jian() {
        if (istrue > 0) {
            istrue -= 1;
            invalidate();
        }
    }

在这里我因为方便就没有去将相关属性写成自定义除属性,当然有需要的可以自己将其提取出来
源码下载地址:
http://download.csdn.net/detail/w18756901575/9520985

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值