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

来源:互联网 发布:阿里云域名申请 编辑:程序博客网 时间:2024/06/04 23:20

本文使用画笔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;} elsestone.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远点坐标mPointXmPointY以及每个控件与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画出控件

@Overridepublic 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)回调方法将点击事件反馈出去

注:由于画出来的控件是没有点击事件的,所以只能自定义点击事件,大概思路:已知当前所有控件的坐标位置与每个控件的大小,便可知道此控件的面积所在的坐标范围,当有点击事件的时候,判断是否在控件的面积之内,便可实现点击效果。

0 0
原创粉丝点击