1.在values建立attrs.xml,写出你需要的属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="firstColor" format="color" />
<attr name="secondColor" format="color" />
<attr name="circleWidth" format="dimension" />
<attr name="dotCount" format="integer" />
<attr name="splitSize" format="integer" />
<attr name="bg" format="reference" /> <declare-styleable name="CustomVolumControlBar">
<attr name="firstColor" />
<attr name="secondColor" />
<attr name="circleWidth" />
<attr name="dotCount" />
<attr name="splitSize" />
<attr name="bg" />
</declare-styleable> </resources>

2.创建view类并实现所需要的业务,具体看代码,代码中写的很详细:

package com.zzw.Custom.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.AudioManager;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View; import com.zzw.Custom.R; /**
* Created by zzw on 2016/6/1.
* 描述:
*/
public class CustomVolumControlBar extends View { /**
* 第一圈的颜色
*/
private int mFirstColor; /**
* 第二圈的颜色
*/
private int mSecondColor;
/**
* 圈的宽度
*/
private int mCircleWidth;
/**
* 画笔
*/
private Paint mPaint;
/**
* 当前进度
*/
private int mCurrentCount = 3; /**
* 中间的图片
*/
private Bitmap mImage;
/**
* 每个块块间的间隙
*/
private int mSplitSize;
/**
* 个数
*/
private int mCount; /**
* 中间图片界限
*/
private Rect mRect; private AudioManager mAudioManager; private Handler mHandler = new Handler(); public CustomVolumControlBar(Context context) {
this(context, null);
} public CustomVolumControlBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public CustomVolumControlBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
} private void init(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomVolumControlBar, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomVolumControlBar_firstColor:
this.mFirstColor = a.getColor(attr, Color.BLACK);
break; case R.styleable.CustomVolumControlBar_secondColor:
this.mSecondColor = a.getColor(attr, Color.WHITE);
break; case R.styleable.CustomVolumControlBar_circleWidth:
this.mCircleWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
break; case R.styleable.CustomVolumControlBar_dotCount:
this.mCount = a.getInt(attr, 20);// 默认20
break; case R.styleable.CustomVolumControlBar_splitSize:
this.mSplitSize = a.getInt(attr, 20);
break; case R.styleable.CustomVolumControlBar_bg:
this.mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
break;
}
}
a.recycle();
mPaint = new Paint();
mRect = new Rect();
if (mAudioManager == null)
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); /**
* 获取到最大音量和当前音量
*/
mCount = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mCurrentCount = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); Log.e("=====", "mCount:" + mCount + " mCurrentCount:" + mCurrentCount);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); mPaint.setAntiAlias(true);//消除锯齿
mPaint.setStrokeWidth(mCircleWidth);//设置圆圈宽度
mPaint.setStrokeCap(Paint.Cap.ROUND);//定义线段电形状圆头
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);//设置空心
int centre = getWidth() / 2;//得到圆心
int radius = centre - mCircleWidth / 2;//得到半径 drawOval(canvas, centre, radius); /**
* 计算内切正方形的位置
*/
int relRadius = radius - mCircleWidth / 2;// 获得内圆的半径
/**
* 内切正方形的距离顶部 = mCircleWidth + relRadius - √2 / 2
*/
mRect.left = (int) (relRadius - Math.sqrt(2) * 1.0f / 2 * relRadius) + mCircleWidth; /**
* 内切正方形的距离左边 = mCircleWidth + relRadius - √2 / 2
*/
mRect.top = (int) (relRadius - Math.sqrt(2) * 1.0f / 2 * relRadius) + mCircleWidth; mRect.bottom = (int) (mRect.left + Math.sqrt(2) * relRadius);
mRect.right = (int) (mRect.left + Math.sqrt(2) * relRadius); /**
* 如果图片比较小,那么根据图片的尺寸放置到正中心
*/
if (mImage.getWidth() < Math.sqrt(2) * relRadius) {
mRect.left = (int) (mRect.left + Math.sqrt(2) * relRadius * 1.0f / 2 - mImage.getWidth() * 1.0f / 2);
mRect.top = (int) (mRect.top + Math.sqrt(2) * relRadius * 1.0f / 2 - mImage.getHeight() * 1.0f / 2);
mRect.right = (int) (mRect.left + mImage.getWidth());
mRect.bottom = (int) (mRect.top + mImage.getHeight());
}
// 绘图
canvas.drawBitmap(mImage, null, mRect, mPaint);
} /**
* 画块块去
*/
private void drawOval(Canvas canvas, int centre, int radius) { /**
* 根据需要画的个数以及间隙计算每个块块所占的比例*360
*/
float itemSize = (360 * 1.0f - mCount * mSplitSize) / mCount;
/**
* 用于定义的圆弧的形状和大小的界限
*/
RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius);
mPaint.setColor(mFirstColor);// 设置圆环的颜色
for (int i = 0; i < mCount; i++) {
canvas.drawArc(oval, i * (itemSize + mSplitSize), itemSize, false, mPaint);// 根据进度画圆弧
}
mPaint.setColor(mSecondColor); // 设置圆环的颜色
for (int i = 0; i < mCurrentCount; i++) {
canvas.drawArc(oval, i * (itemSize + mSplitSize), itemSize, false, mPaint); // 根据进度画圆弧
}
} /**
* 当前数量+1
*/
public synchronized void up() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mCurrentCount++;
if (mCurrentCount > mCount)
mCurrentCount = mCount; postInvalidate();
setVolume(mCurrentCount);
}
}, 100);
} /**
* 设置音量
*
* @param index
*/
private void setVolume(int index) {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 1);
} /**
* 当前数量-1
*/
public synchronized void down() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mCurrentCount--;
if (mCurrentCount < 0)
mCurrentCount = 0;
postInvalidate();
setVolume(mCurrentCount);
}
}, 100);
} private int lastY, nowY; @Override
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = (int) event.getY();
break; case MotionEvent.ACTION_MOVE:
nowY = (int) event.getY();
int updateYCount = (nowY - lastY) / 30;
if (updateYCount > 0) {
for (int i = 0; i < updateYCount; i++) {
down();
}
} else if (updateYCount < 0) {
for (int i = updateYCount; i < 0; i++) {
up();
}
}
lastY = nowY;
break;
}
return true;
}
}

3.在xml中引用:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.zzw.Custom.MainActivity"> <com.zzw.Custom.widget.CustomVolumControlBar
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
app:bg="@mipmap/ic_horn"
app:circleWidth="5dp"
app:firstColor="@color/colorPrimary"
app:secondColor="@color/colorAccent"
app:splitSize="10" />
</RelativeLayout>

当然,在实际操作中OnTouch事件一般是放在activity或者Fragment里面的,只需在代码中复制出去即可

最后十分感谢鸿洋大神,让我们学到了很多,该篇与鸿洋大神相关的的博客地址:http://blog.csdn.net/lmj623565791/article/details/24529807

CustomVolumControlBar

基于鸿洋博客自定于View实现的android音量调节控件的更多相关文章

  1. 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  2. 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  3. 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  4. 基于.NetCore开发博客项目 StarBlog - (12) Razor页面动态编译

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  5. 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  6. 基于.NetCore开发博客项目 StarBlog - (17) 自动下载文章里的外部图片

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  7. 象写程序一样写博客:搭建基于github的博客

    象写程序一样写博客:搭建基于github的博客   前言 github 真是无所不能.其 Pages 功能 支持上传 html,并且在页面中显示.于是有好事者做了一个基于 github 的博客管理工具 ...

  8. Lucene5.5.4入门以及基于Lucene实现博客搜索功能

    前言 一直以来个人博客的搜索功能很蹩脚,只是自己简单用数据库的like %keyword%来实现的,所以导致经常搜不到想要找的内容,而且高亮显示.摘要截取等也不好实现,所以决定采用Lucene改写博客 ...

  9. 基于Hexo搭建博客并部署到Github Pages

    基于Hexo搭建博客并部署到Github Pages 之前在简书上写东西,觉得自己还是太浮躁.本来打算用Flask自己写一个,以为是微框架就比较简单,naive.HTML.CSS.JS等都要学啊,我几 ...

随机推荐

  1. MapX小试

    需MapX 控件 string layerName = "12Q3_new"; string tabFile = string.Format(@"E:\map\地图\现在 ...

  2. junit在idea中的使用(2)--实践篇

    目录:(1)普通java项目(2)在web项目中 (1)普通java项目 直接在代码中写上 @Before @Test即可,想执行main方法,直接右击main,选择run as import org ...

  3. Openstak(M版)计算节点安装

    #############修改hosts文件 10.0.0.11 controller10.0.0.31 compute110.0.0.32 compute210.0.0.41 block110.0. ...

  4. C# partial 关键字

    C# partial关键字详解 partial关键字允许把类.结构或接口放在多个文件中.一般情况下,一个类存储在单个文件中.但有时,多个开发人员需要访问同一个类,或者某种类型的代码生成器生成了一个类的 ...

  5. OpenGL学习进程(3)第一课:初始化窗体

        本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体:     (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <st ...

  6. octotree神器 For Github and GitLab 火狐插件

    Code tree for GitHub and GitLabExtension to show code tree for GitHub and GitLab. Useful for develop ...

  7. CSS 命名里面有大学问

    其实迟迟不敢开始写关于样式里布局方面的心得, 因为大多数人眼中,哪需要管那么多,只需要最终效果达到了就行了呗. 然而,即使是如今国内外顶级大牛也不敢说自己是个优秀的 CSS 工程师. 一般大公司都是 ...

  8. uboot相关的几篇好文

    http://www.eeworld.com.cn/mcu/2015/0727/article_21246.html http://blog.csdn.net/kernel_yx/article/de ...

  9. LVS/DR 配置

    LVS/DR 配置 实验环境 三台主机:Linux Centos 6.4 32位 调度器Director:192.168.1.160(公网IP).192.168.1.100(VIP) HTTP真实服务 ...

  10. 20145210姚思羽《网络对抗》MSF基础应用实验

    20145210姚思羽<网络对抗>MSF基础应用实验 实验后回答问题 1.用自己的话解释什么是exploit,payload,encode. exploit就是进行攻击的那一步 paylo ...