首页 > 其他 > 详细

自定义椭圆控制界面

时间:2015-03-24 19:19:07      阅读:220      评论:0      收藏:0      [点我收藏+]

其它的先不说,我们先看看效果图,如下:

技术分享

这东西,其实不难,就是要计算各个点的位置是比较蛋疼的,还有一个地方就是画扇形的时候,不知道为什么得不到我想要的效果,具体描述,可以看我的代码:

package com.example.a;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

/**
 * 一个椭圆分区的按钮集界面,没有写成控件的形式,毕竟自定义这东西,还是得按照项目需求来
 * 
 * @author zhoudailiang
 * @since 2015-3-24 17:49
 */
public class ShapeView extends View implements OnTouchListener{

	private int radius = 40; // 中间小圆的半径
	private Paint mPaint;
	private RectF oval;
	private int width, height;
	private boolean top, right, bottom, left, center;
	private ShapeViewListener onShapListener;
	
	//回调,进行各个部分的事件监听
	public interface ShapeViewListener {
		public void onTopListener();
		public void onRightListener();
		public void onBottomListener();
		public void onLeftListener();
		public void onCenterListener();
	}
	
	public void setOnShapeListener(ShapeViewListener onShapListener) {
		this.onShapListener = onShapListener;
	}
	
	public ShapeView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	public ShapeView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public ShapeView(Context context) {
		super(context);
		init();
	}
	
	private void init() {
		mPaint = new Paint();
		//设置背景为天蓝色
		setBackgroundColor(0xFF436EEE);
		setOnTouchListener(this);
	}
	
	@SuppressLint("DrawAllocation")
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//得到布局的宽度
		width = this.getMeasuredWidth();
		height = 2 * width / 3;
		//画椭圆的矩形区域
		oval = new RectF(5, 5, width - 5, height - 5);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		mPaint.setStrokeWidth(2);
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Style.STROKE);
		mPaint.setColor(0xffffffff);
		canvas.drawArc(oval, 0, 360, false, mPaint);
		canvas.drawCircle(width / 2, height / 2, radius, mPaint);
		if (center) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xaaffffff);
			canvas.drawCircle(width / 2, height / 2, radius, mPaint);
		}
		
		//下面这里的扇形范围-56, 112是我调试出来的,MD,不知道为什么-45, 90这样的写法就是有问题,
		//各位看官,如果知道为什么,还望不吝指教
		if (right) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xaaffffff);
			canvas.drawArc(oval, -56, 112, true, mPaint);
		}
		
		if (bottom) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xaaffffff);
			canvas.drawArc(oval, 57, 66, true, mPaint);
		}
		
		if (left) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xaaffffff);
			canvas.drawArc(oval, 124, 112, true, mPaint);
		}
		
		if (top) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xaaffffff);
			canvas.drawArc(oval, 237, 66, true, mPaint);
		}
			
		//如果上下左右被按了,为了中间的部分不显示,这里画圆遮住了那部分白色
		if (right || top || bottom || left) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(0xFF436EEE);
			canvas.drawCircle(width / 2, height / 2, 38, mPaint);
		}
		
		mPaint.setStyle(Style.STROKE);
		mPaint.setColor(0xffffffff);
		mPaint.setStrokeWidth(1);
		mPaint.setAlpha(100);
		//根据标准椭圆公式,求得的一个量,我们这里只用再进行坐标变换,就可以得到四个在椭圆上的点了
		float t = getCoordinate(width - 10, height - 10);
		//四条区域分割线的起始坐标
		float[] pts = {
				width / 2 + getSF(radius), height / 2 + getSF(radius), width / 2 + t, height / 2 + t,
				width / 2 - getSF(radius), height / 2 + getSF(radius), width / 2 - t, height / 2 + t,
				width / 2 + getSF(radius), height / 2 - getSF(radius), width / 2 + t, height / 2 - t,
				width / 2 - getSF(radius), height / 2 - getSF(radius), width / 2 - t, height / 2 - t};
		canvas.drawLines(pts, mPaint);
	}

	private float getCoordinate(int w, int h) {
		return (float) ((w * h) / (Math.sqrt(w*w + h*h) * 2));
	}
	
	/** 得到圆形的直角边的长度 */
	private float getSF(int a) {
		return (float) (a / Math.sqrt(2));
	}
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				float x = event.getX();
				float y = event.getY();
				//不在椭圆内,什么处理都不做
				if (!isInOval(x, y)) {
					return false;
				}
				if (isInCricle(x,y)) {
					center = true;
					if (onShapListener != null) {
						onShapListener.onCenterListener();
					}
				} else {
					float a = x - y - (width - height) / 2;
					float b = x + y - (width + height) / 2;
					if (a > 0) {
						if (b > 0) {
							right = true;
							if (onShapListener != null) {
								onShapListener.onRightListener();
							}
						} else {
							top = true;
							if (onShapListener != null) {
								onShapListener.onTopListener();
							}
						}
					} else {
						if (b > 0) {
							bottom = true;
							if (onShapListener != null) {
								onShapListener.onBottomListener();
							}
						} else {
							left = true;
							if (onShapListener != null) {
								onShapListener.onLeftListener();
							}
						}
					}
				}
				invalidate();
				break;
			case MotionEvent.ACTION_UP:
				top = false;
				right = false;
				bottom = false;
				left = false;
				center = false;
				invalidate();
				break;
		}
		return true;
	}
	
	/** (x, y)是否在椭圆内部 */
	private boolean isInOval(float x, float y) {
		float tmp = (2*x/width - 1) * (2*x/width - 1) + (2*y/height - 1) * (2*y/height - 1);
		if (tmp <= 1) {
			return true;
		} else {
			return false;
		}
	}
	
	/** (x, y)是否在中间圆里面 */
	private boolean isInCricle(float x, float y) {
		float tmp = (x - width/2) * (x - width/2) + (y - height/2) * (y - height/2);
		if (tmp <= radius * radius) {
			return true;
		} else {
			return false;
		}
	}
}

这里是调用的代码:

private ShapeView.ShapeViewListener listener;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		ShapeView view = new ShapeView(this);
		FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
		view.setLayoutParams(lp);
		setContentView(view);
		
		listener = new ShapeView.ShapeViewListener() {
			
			@Override
			public void onTopListener() {
				show("top");
			}
			
			@Override
			public void onRightListener() {
				show("right");
			}
			
			@Override
			public void onLeftListener() {
				show("left");
			}
			
			@Override
			public void onCenterListener() {
				show("center");
			}
			
			@Override
			public void onBottomListener() {
				show("bottom");
			}
		};
		view.setOnShapeListener(listener);
}

上面的show函数,是一个封装了的Toast显示。

OK,这篇文章结束了。

自定义椭圆控制界面

原文:http://blog.csdn.net/zhoudailiang/article/details/44595539

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!