您的位置:首页 > 移动开发 > Android开发

android 自己动手画一个圆形菜单

2015-03-24 15:31 387 查看
本文使用画笔Paint来自定义一个半圆形的菜单 如下图:



demo下载地址:http://download.csdn.net/detail/suyiyang888/8528707

一、定义类CircleMenu继承View,重写三个构造函数

二、在onLayout(boolean changed, int left, int top, int right,int bottom)方法中可以获取到此view在屏幕上的上下左右坐标。通过x = right - left,y = bottom - top可计算出当前view的尺寸,为接下来画圆做准备。

三、初始化

1、由于屏幕尺寸的不同,所以导致当前view的尺寸是不定的,只能通过计算来获取当前圆形菜单的半径(此计算方法是我经过多尺寸手机的实际测试计算出来的),这里得到的不是整个圆,而是大半圆,所以圆点坐标往X轴正方向移动了大概1/3

mPaint.setColor(666885);
mPaint.setStrokeWidth(6);
setBackgroundResource(R.drawable.bg);
dvlue = 0;// 做适配屏幕处理
if (x >= y) {
minSize = y;
dvlue = x - y;
} else {
minSize = x;
dvlue = y - x;
}
if (dvlue > 180) {
mPointX = x / 3 * 2 + minSize / 10;
mPointY = y / 2 + minSize / 20;
mRadius = minSize / 2 + minSize / 20;
} else if (dvlue > 90) {
type = 2;
mPointX = x / 3 * 2 + minSize / 30;
mPointY = y / 2 + minSize / 30;
mRadius = minSize / 2 - minSize / 60;
} else {
type = 3;
mPointX = x / 3 * 2;
mPointY = y / 2 + minSize / 30;
mRadius = minSize / 2 - minSize / 12;
}
if (mRadius * 2 + (minSize / 4 / 2) > y) {
mRadius = mRadius - (mRadius * 2 + minSize / 4 / 2 - y);
}

2、初始化每个控件

a、先创建控件实体类Stone

class Stone {
// 图片
Bitmap bitmap;
// 角度
int angle;
// x坐标
float x;
// y坐标
float y;
// 是否可见
boolean isVisible = true;
}
b、初始化每个控件angle是菜单的起始角度,mDegreeDelta
是每个控件之间的间隔角度STONE_COUNT是菜单中选项的个数,通过计算当前view的尺寸来决定每个控件的大小,这步能够得到每个控件与X轴的角度,下一步通过半径与这个角度来得到控件在圆形菜单上的坐标

private void initStones() {
mStones = new Stone[STONE_COUNT];
mStones2 = new Stone[STONE_COUNT];
Stone stone;
Stone stone2;
int angle = 130;
mDegreeDelta = 43;
for (int index = 0; index < STONE_COUNT; index++) {
stone = new Stone();
stone2 = new Stone();
if (index != 0) {
stone.angle = angle;
angle += mDegreeDelta;
} else
stone.angle = 0;
Bitmap b = BitmapFactory.decodeResource(getResources(), rec[index]);
float width = 0;
if (index != 0) {
width = (minSize / 4 - type * 5) / (float) b.getWidth();
} else {
width = (minSize / 2 - type * 15) / (float) b.getWidth();
}
if (width <= 0) {
width = 1;
}
Matrix matrix = new Matrix();
matrix.postScale(width, width);
stone.bitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
b.getHeight(), matrix, true);
mStones[index] = stone;
width += 0.1;
Matrix matrix2 = new Matrix();
matrix2.postScale(width, width);
stone2.bitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
b.getHeight(), matrix2, true);
mStones2[index] = stone2;
}
}

C、计算每个控件的坐标,知道了半径mRadius远点坐标mPointX、mPointY以及每个控件与X轴的角度,这样就构成了一个直角三角形,通过正弦定理和余弦定理就能确定控件距离X、Y轴的距离,然后加上圆点坐标,就得到了每个控件的坐标。

private void computeCoordinates() {
Stone stone;
for (int index = 0; index < STONE_COUNT; index++) {
stone = mStones[index];
if (index != 0) {
stone.x = mPointX
+ (float) (mRadius * Math.cos(stone.angle * Math.PI
/ 180));
stone.y = mPointY
+ (float) (mRadius * Math.sin(stone.angle * Math.PI
/ 180));
} else {
if (dvlue > 180) {
stone.x = mPointX - minSize / 15;
stone.y = mPointY + minSize / 20;
} else if (dvlue > 90) {
stone.x = mPointX;
stone.y = mPointY + minSize / 20;
} else {
stone.x = mPointX + minSize / 18;
stone.y = mPointY + minSize / 20;
}
}
ViewParam vp = new ViewParam();
vp.startX = (int) (stone.x - stone.bitmap.getWidth() / 2);
vp.endX = (int) (stone.x + stone.bitmap.getWidth() / 2);
vp.startY = (int) (stone.y - stone.bitmap.getHeight() / 2);
vp.endY = (int) (stone.y + stone.bitmap.getHeight() / 2);
vl.add(vp);
}

四、在onDraw(Canvas canvas)方法中使用canvas.drawPoint、canvas.drawBitmap画出控件

@Override
public void onDraw(Canvas canvas) {
/**
* 画虚线
*/
for (int i = 0; i < 360; i = i + 4) {
mPaint.setAlpha(alp);
if (i < 180) {
if (alp < 256 - malp)
alp += malp * 5;
if (alp > 180)
alp = 180;
} else {
if (alp > malp)
alp -= malp * 5;
if (alp < 0)
alp = 0;
}
canvas.drawPoint(
mPointX + (float) (mRadius * Math.cos(i * Math.PI / 180)),
mPointY + (float) (mRadius * Math.sin(i * Math.PI / 180)),
mPaint);
}
/**
* 画控件
*/

for (int index = 0; index < STONE_COUNT; index++) {
if (!mStones[index].isVisible)
continue;
if (selectItem == currItem && selectItem >= 0
&& selectItem == index) {// 按下
transBitmap = mStones[index].bitmap;
mStones[index].bitmap = mStones2[index].bitmap;
mStones2[index].bitmap = transBitmap;
isNarrow = true;
} else if (currItem >= 0 && currItem != selectItem
&& currItem == index && isNarrow) {// 抬起
transBitmap = mStones[index].bitmap;
mStones[index].bitmap = mStones2[index].bitmap;
mStones2[index].bitmap = transBitmap;
currItem = -1;
isNarrow = false;
}
drawCenter(canvas, mStones[index].bitmap, mStones[index].x,
mStones[index].y);
}
if (selectItem < 0 && currItem >= 0 && !isNarrow) {
selectItem = -1;
currItem = -1;
isNarrow = false;
}
}
五、添加点击事件

在dispatchTouchEvent(MotionEvent event)中处理事件

1、在MotionEvent.ACTION_DOWN:中记录当前点击的坐标及控件状态

2、在MotionEvent.ACTION_UP中处理各种情况

3、通过setOnMenuClickListener(MainMeunClickListener m)回调方法将点击事件反馈出去

注:由于画出来的控件是没有点击事件的,所以只能自定义点击事件,大概思路:已知当前所有控件的坐标位置与每个控件的大小,便可知道此控件的面积所在的坐标范围,当有点击事件的时候,判断是否在控件的面积之内,便可实现点击效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  自定义圆形菜单