这是效果图,自己加了一个渐变的颜色,模仿鸿神做的,自己试了一下,做个笔记。鸿神的文章: Android 自定义View (四) 视频音量调控
当然鸿神里边我认为有一点儿小问题,就是那个mSplitSize我认为应该变换成角度。
自己不做不知道,做的时候还是发现了一些问题,何况多练习一下比较好,比如说那个角度的问题,比如说那个绘制渐变时的问题,只有自己实验了才知道问题。。。
代码如下:
package com.shj.view;
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.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import com.shj.test.R;
public class CircleVolumeView extends View {
private int firstColor;
private int secondColor;
private int dotCount;
private int circleWidth;
private int splitSize;
private Bitmap mImage;
private Paint mPaint;
private Paint gradientPaint;
private Rect mRect;
private int mCurrentCount = 4;
private Matrix matrix;
int downY = 0;//摁下时Y坐标
int lastY = 0;//离开屏幕时Y坐标
public CircleVolumeView(Context context) {
this(context, null);
}
public CircleVolumeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleVolumeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
mPaint = new Paint();
gradientPaint = new Paint();
mRect = new Rect();
matrix = new Matrix();
}
/**
* 一些属性的初始化
* @param context
* @param attrs
*/
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleVolumeView);
firstColor = a.getColor(R.styleable.CircleVolumeView_firstCorlor, Color.parseColor("#dddddd"));
secondColor = a.getColor(R.styleable.CircleVolumeView_secondColor, Color.parseColor("#00ff00"));
dotCount = a.getInt(R.styleable.CircleVolumeView_dotCount, 8);
circleWidth = a.getDimensionPixelSize(R.styleable.CircleVolumeView_circleWidth, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
splitSize = a.getDimensionPixelSize(R.styleable.CircleVolumeView_splitSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()));
mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(R.styleable.CircleVolumeView_middleImg, R.mipmap.ic_launcher));
a.recycle();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = y;
break;
case MotionEvent.ACTION_UP:
lastY = y;
if ((lastY - downY) > 50 && (mCurrentCount > 0)) {//一点点小判断
mCurrentCount--;
postInvalidate();
} else if((lastY - downY) < -50 && (mCurrentCount < dotCount)) {
mCurrentCount++;
postInvalidate();
}
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(circleWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStyle(Paint.Style.STROKE);
gradientPaint.setAntiAlias(true);
gradientPaint.setStrokeWidth(circleWidth);
gradientPaint.setStrokeCap(Paint.Cap.ROUND);
gradientPaint.setStyle(Paint.Style.STROKE);
int center = getWidth() / 2;
int radius = center - circleWidth / 2;
drawOval(canvas, center, radius);
/**
* 这块是计算图片摆放位置内切圆的算法,看大神写的算法的时候,也有点儿郁闷,其实这个不用看
* 自己一画就知道了,鸿神的只是化解了。
*/
int includeRadius = center - circleWidth;
mRect.left = (int) (circleWidth + (includeRadius - Math.sqrt(2) * 1.0f / 2 * includeRadius));
mRect.top = (int) (circleWidth + (includeRadius - Math.sqrt(2) * 1.0f / 2 * includeRadius));
mRect.right = (int) (getWidth() / 2 + Math.sqrt(2) * 1.0f / 2 * includeRadius);
mRect.bottom = (int) (getWidth() / 2 + Math.sqrt(2) * 1.0f / 2 * includeRadius);
canvas.drawBitmap(mImage, null, mRect, mPaint);
}
private void drawOval(Canvas canvas, int center, int radius) {
float spliteDegree = (float) (splitSize * 360 * 1.0f / (2 * radius * Math.PI));//间隔的角度
float itemSize = (360 * 1.0f - spliteDegree * dotCount) / dotCount;//绘制的角度
RectF oval = new RectF(center - radius, center - radius, center + radius, center + radius);
//绘制外边的圆
mPaint.setColor(firstColor);
for (int i = 0; i < dotCount; i++) {
canvas.drawArc(oval, (i * (itemSize + spliteDegree)), itemSize, false, mPaint);
}
SweepGradient sweepGradient = new SweepGradient(center, center, new int[]{Color.BLUE, Color.GREEN, Color.RED}, null);//着色器
matrix.setRotate(-5, center, center);//这个-5的角度偏移量时因为使用的 Paint.Cap.ROUND 时,两边会出现突出的圆弧,不知道有没有准确计算偏移量的算法,这里的-5是个大概的值
sweepGradient.setLocalMatrix(matrix);
gradientPaint.setShader(sweepGradient);//为什么要用两个画笔,因为绘制的渐变,不适用两个画笔的话,这个渐变开始的时候就会被绘制完全,是一个完整的渐变环形,无论时多少的进度
for (int i = 0; i < mCurrentCount; i++) {
canvas.drawArc(oval, (i * (itemSize + spliteDegree)), itemSize, false, gradientPaint);
}
}
}