今天没事逛eoe,看见有人求助要做一个下面的效果,我看下面一哥们说要用12张图片,这尼玛逆天的麻烦,仔细看了一下感觉自定义控件木有问题,就花点时间写了一个。
好了,进入正题,继续我们的自定义View四部曲。
1、先分许需要的属性,两个小块的颜色、一张中间的图片、间隙大小、一个多少个块块。分析完毕,开始写attr.xml
-
"1.0" encoding="utf-8" xml version=
-
<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"> </attr>
-
-
<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、在构造中获取这些属性:
-
/**
-
* 第一圈的颜色
-
*/
-
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;
-
-
public CustomVolumControlBar(Context context, AttributeSet attrs)
-
{
-
this(context, attrs, 0);
-
}
-
-
public CustomVolumControlBar(Context context)
-
{
-
this(context, null);
-
}
-
-
/**
-
* 必要的初始化,获得一些自定义的值
-
*
-
* @param context
-
* @param attrs
-
* @param defStyle
-
*/
-
public CustomVolumControlBar(Context context, AttributeSet attrs, int defStyle)
-
{
-
super(context, attrs, defStyle);
-
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomVolumControlBar, defStyle, 0);
-
int n = a.getIndexCount();
-
-
for ( int i = 0; i < n; i++)
-
{
-
int attr = a.getIndex(i);
-
switch (attr)
-
{
-
case R.styleable.CustomVolumControlBar_firstColor:
-
mFirstColor = a.getColor(attr, Color.GREEN);
-
break;
-
case R.styleable.CustomVolumControlBar_secondColor:
-
mSecondColor = a.getColor(attr, Color.CYAN);
-
break;
-
case R.styleable.CustomVolumControlBar_bg:
-
mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
-
break;
-
case R.styleable.CustomVolumControlBar_circleWidth:
-
mCircleWidth = a.getDimensionPixelSize(attr, ( int) TypedValue.applyDimension(
-
TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
-
break;
-
case R.styleable.CustomVolumControlBar_dotCount:
-
mCount = a.getInt(attr, 20); // 默认20
-
break;
-
case R.styleable.CustomVolumControlBar_splitSize:
-
mSplitSize = a.getInt(attr, 20);
-
break;
-
}
-
}
-
a.recycle();
-
mPaint = new Paint();
-
mRect = new Rect();
-
}
3、重写onDraw
-
-
protected void onDraw(Canvas canvas)
-
{
-
mPaint.setAntiAlias( true); // 消除锯齿
-
mPaint.setStrokeWidth(mCircleWidth); // 设置圆环的宽度
-
mPaint.setStrokeCap(Paint.Cap.ROUND); // 定义线段断电形状为圆头
-
mPaint.setAntiAlias( true); // 消除锯齿
-
mPaint.setStyle(Paint.Style.STROKE); // 设置空心
-
int centre = getWidth() / 2; // 获取圆心的x坐标
-
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);
-
}
-
-
/**
-
* 根据参数画出每个小块
-
*
-
* @param canvas
-
* @param centre
-
* @param radius
-
*/
-
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); // 根据进度画圆弧
-
}
-
}
这里需要注意下:
画块:首先根据块数量和间隙计算,每个块所占的比例。
画图:当图比较大时,直接使用该环内切正方形大小进行约束,当图片比较小时,在正中心的位置绘制。有些数学运算过程,楼主在草稿上画了一会,不复杂,大家自己画画,我就不贴草稿了。
4、添加触摸监听:
-
/**
-
* 当前数量+1
-
*/
-
public void up()
-
{
-
mCurrentCount++;
-
postInvalidate();
-
}
-
-
/**
-
* 当前数量-1
-
*/
-
public void down()
-
{
-
mCurrentCount--;
-
postInvalidate();
-
}
-
-
private int xDown, xUp;
-
-
-
public boolean onTouchEvent(MotionEvent event)
-
{
-
-
switch (event.getAction())
-
{
-
case MotionEvent.ACTION_DOWN:
-
xDown = ( int) event.getY();
-
break;
-
-
case MotionEvent.ACTION_UP:
-
xUp = ( int) event.getY();
-
if (xUp > xDown) // 下滑
-
{
-
down();
-
} else
-
{
-
up();
-
}
-
break;
-
}
-
-
return true;
-
}
最后,效果图:
可惜楼主尼玛是找不到那个音量的图,不要叫我去抠图哈,就随便拿了几张图片来试试。