Android圆盘菜单(修改了网络上现有的demo总是显示第一个的bug,以及增加了点击事件)

导语:最近项目中要用的圆盘菜单,在网上找了一圈发现现有的demo都不能拿过来直接用因为都是太基础了,所以自己在原有的基础上修改了下,增加了点击事件以及修正了滑动后总是从第一个开始绘图的bug。


package chroya.demo.roundspin;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

/**
 * 圆盘式的view
 * @author chroya
 *
 */
public class RoundSpinView extends View {
	private Paint mPaint = new Paint();

	private BigStone[] mStones;
	private static final int STONE_COUNT = 21;
	private int mPointX=0, mPointY=0;
	private int mRadius = 0;
	private int mDegreeDelta;
	private boolean isAllowed = false;
	private boolean isMove = false;
	private BigStone currentbstone = null;

	public RoundSpinView(Context context, int px, int py, int radius) {
		super(context);
		mPaint.setColor(Color.RED);
		mPaint.setStrokeWidth(2);
		setBackgroundResource(R.drawable.menubkground);

		mPointX = px;
		mPointY = py;
		mRadius = radius;

		setupStones();
		computeCoordinates();
	}

	/**
	 * 初始化
	 */
	private void setupStones() {

		mStones = new BigStone[STONE_COUNT];
		BigStone stone;
		int angle = 0;
		mDegreeDelta = 360/STONE_COUNT;

		for(int index=0; index<STONE_COUNT; index++) {
			stone = new BigStone();
			stone.index = index;
			stone.content = index + "";
			stone.angle = angle;
			stone.bitmap = drawNumAtBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon),index);
			//增加点击事件
			stone.action = new ActionEvent(){
				@Override
				public void action(BigStone stone) {
					Toast.makeText(RoundSpinView.this.getContext(), "你点击了我 ! " + stone.content, Toast.LENGTH_SHORT).show();
				}
			};
			angle += mDegreeDelta;
			mStones[index] = stone;
		}
	}

	/**
	 * 重新计算每一个元素的坐标位置
	 * @param x
	 * @param y
	 */
	private void resetStonesAngle(float x, float y) {
		int angle = computeCurrentAngle(x, y);
		for(int index=0; index<STONE_COUNT; index++) {
			//从下标为0的开始
			for(BigStone bs : mStones){
				if(bs.index == index){
					bs.angle = angle;
					break;
				}
			}
			angle += mDegreeDelta;
		}
	}

	private void computeCoordinates() {
		for(BigStone stone : mStones) {
			stone.x = mPointX+ (float)(mRadius * Math.cos(stone.angle*Math.PI/180));
			stone.y = mPointY+ (float)(mRadius * Math.sin(stone.angle*Math.PI/180));
		}
	}

	/**
	 * 计算手指划过的线性距离
	 * @param x
	 * @param y
	 * @return
	 */
	private int computeCurrentAngle(float x, float y) {		
		float distance = (float)Math.sqrt(((x-mPointX)*(x-mPointX) + (y-mPointY)*(y-mPointY)));
		int degree = (int)(Math.acos((x-mPointX)/distance)*180/Math.PI);
		if(y < mPointY) {
			degree = -degree;
		}
		return degree;
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		if(event.getAction() == MotionEvent.ACTION_DOWN){
			isMove = false;
			int index = 0;
			float min = 320;
			//求出点击坐标X值与那么元素的坐标位置X值最为接近
			for(BigStone bs : mStones){
				if(bs.x >= 0 && bs.x <= 320 && min >= Math.max(bs.x, event.getX()) - Math.min(bs.x, event.getX())){
					min = Math.max(bs.x, event.getX()) - Math.min(bs.x, event.getX());
					index = bs.index;
				}
			}
			//或者该元素内容
			for(BigStone bs : mStones){
				if(bs.index == index){
					currentbstone = bs;
					break;
				}
			}
			//判断Y值是否也为最接近(可根据自己情况是否增加这段逻辑)
			if(currentbstone.y >= 0 && currentbstone.y <= 430 && 80 >= Math.max(currentbstone.y, event.getY()) - Math.min(currentbstone.y, event.getY())){
				isAllowed = true;
				if(index > 0){
					for(BigStone bs : mStones){
						if(bs.index >= index){
							bs.index = bs.index - index;
						}else{
							bs.index += STONE_COUNT - index;
						}
					}
				}
			}else{
				isAllowed = false;
			}
		}
		if(event.getAction() == MotionEvent.ACTION_MOVE && isAllowed){
			isMove = true;
			resetStonesAngle(event.getX(), event.getY());
			computeCoordinates();
			invalidate();
		}
		if(event.getAction() == MotionEvent.ACTION_UP && isAllowed){
			if(!isMove)
				currentbstone.action.action(currentbstone);
		}
		return true;
	}

	@Override
	public void onDraw(Canvas canvas) {
		canvas.drawPoint(mPointX, mPointY, mPaint);
		for(int index=0; index<STONE_COUNT; index++) {
			for(BigStone bs : mStones){
				if(bs.index == index){
					drawInCenter(canvas, bs.bitmap, bs.x, bs.y);
					canvas.drawLine(mPointX, mPointY, bs.x, bs.y, mPaint);
					break;
				}
			}
		}
	}

	/**
	 * 把中心点放到中心处
	 * @param canvas
	 * @param bitmap
	 * @param left
	 * @param top
	 */
	void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top) {
		canvas.drawPoint(left, top, mPaint);
		canvas.drawBitmap(bitmap, left-bitmap.getWidth()/2, top-bitmap.getHeight()/2, null);
	}

	interface ActionEvent{
		public void action(BigStone stone);
	}

	class BigStone {

		int index;
		//图片
		Bitmap bitmap;

		//角度
		int angle;

		//x坐标
		float x;

		//y坐标
		float y;

		String content;

		ActionEvent action;
	}

	public static Bitmap drawNumAtBitmap(Bitmap bitmap, int num) {
		int x = bitmap.getWidth();
		int y = bitmap.getHeight();
		Bitmap newbit = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(newbit);
		Paint paint = new Paint();
		canvas.drawBitmap(bitmap, 0, 0, paint);
		paint.setColor(Color.RED);
		paint.setTextSize(20);
		if (num >= 10) {
			canvas.drawText(num + "", 9, 25, paint);
		} else {
			canvas.drawText(num + "", 15, 25, paint);
		}
		canvas.save(Canvas.ALL_SAVE_FLAG);
		canvas.restore();
		bitmap.recycle();
		return newbit;
	}
}

package chroya.demo.roundspin;

import android.app.Activity;
import android.os.Bundle;

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new RoundSpinView(getApplicationContext(), 160, 430, 240));
    }
}
我还不会上传源码...研究下上传上来~!

评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值