直接贴代码,不废话了
最主要的就是计算几个点的坐标问题,然后用二阶贝塞尔函数画出连接区域
用p1与p4的中心点作为上半个不规则形状的贝塞尔曲线的的控制点
用p3与p3的中心点作为下半个不规则形状的贝塞尔曲线的的控制点
然后知道起点和重点,实时绘制贝塞尔曲线,然后把封闭区域用红色填充就可以了。
重点在于切点的计算:高中数学学的不好花了很久才算出来。太菜了
PointCom函数的
ComputePoint方法就是计算两条相切的线与两个圆的交点坐标的
/** * 代码写的比较仓猝,以后再优化写法和补充那些数值的具体含义,求勿喷QAQ */ public class RedPointView extends View { private Path mPath; private Paint mFillCirclePaint; PointCom center; /** View的宽度 **/ private int width; /** View的高度,这里View应该是正方形,所以宽高是一样的 **/ private int height; /** View的中心坐标x **/ private int centerX; /** View的中心坐标y **/ private int centerY; private int radius,s_redius; public RedPointView(Context context) { this(context, null, 0); } public RedPointView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RedPointView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mFillCirclePaint = new Paint(); mFillCirclePaint.setColor(Color.RED ); mFillCirclePaint.setStyle(Paint.Style.FILL); mFillCirclePaint.setStrokeWidth(1); mFillCirclePaint.setAntiAlias(true); radius=50; s_redius=20; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); width = getWidth(); height = getHeight(); centerX = width / 2; centerY = height / 2; center=new PointCom(centerX,centerY); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Path path = new Path(); mPath = new Path(); Paint CirclePaint = new Paint(); CirclePaint.setColor(Color.RED); CirclePaint.setStyle(Paint.Style.FILL); CirclePaint.setStrokeWidth(1); CirclePaint.setAntiAlias(true); if (status==0) canvas.drawCircle(centerX,centerY,radius ,CirclePaint); else if (status==1){ //处于拖拽状态 canvas.drawCircle(centerX,centerY,s_redius ,CirclePaint); canvas.drawCircle(currentPoint.x, currentPoint.y, radius, CirclePaint);// 大圆 center.ComputePoint(currentPoint,s_redius); currentPoint.ComputePoint(downPoint,radius); // path.moveTo(center.left.x, center.left.y);// 此点为多边形的起点 // path.lineTo(currentPoint.right.x, currentPoint.right.y); // path.lineTo(currentPoint.left.x, currentPoint.left.y); // path.lineTo(center.right.x, center.right.y); // path.close(); // 使这些点构成封闭的多边形 // canvas.drawPath(path, CirclePaint); Log.e("状态:","拖拽状态,当前位置是:"+currentPoint.x+",,,,"+ currentPoint.y); Log.e("状态:","currentPoint的左右点坐标分别是:("+currentPoint.left.x+"。"+ currentPoint.left.y+"),"+"("+currentPoint.right.x+"。"+ currentPoint.right.y+")"); Log.e("状态:","拖拽状态,中心位置是:"+center.x+",,,,"+ center.y); Log.e("状态:","currentPoint的左右点坐标分别是:("+center.left.x+"。"+ center.left.y+"),"+"("+center.right.x+"。"+ center.right.y+")"); mPath.moveTo(center.left.x,center.left.y); mPath.quadTo( (center.left.x+currentPoint.left.x)/2, (center.left.y+currentPoint.left.y)/2 ,currentPoint.right.x, currentPoint.right.y); mPath.lineTo(currentPoint.left.x,currentPoint.left.y); mPath.quadTo( (center.right.x+currentPoint.right.x)/2, (center.right.y+currentPoint.right.y)/2 ,center.right.x, center.right.y); mPath.close(); canvas.drawPath(mPath, mFillCirclePaint);//用画笔颜色填充mpath图形 }else if (status==2){ //处于游离状态 Log.e("状态:","游离状态,X,Y分别是:"+currentPoint.x+",,,,"+ currentPoint.y); canvas.drawCircle(currentPoint.x, currentPoint.y, radius, CirclePaint);// 大圆 }else if (status==3){ canvas.drawCircle(center.x, center.y, radius, CirclePaint);// 大圆 } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(ev); } int normaldistance=300; boolean isdown=false; PointCom downPoint=new PointCom(); PointCom currentPoint=new PointCom(); int status=0; //0代表初始状态,1代表拖拽状态,2代表游离状态,3代表恢复状态 public class PointCom{ private float x; private float y; PointF left; PointF right; public PointCom() { x=0; y=0; left=new PointF(); right= new PointF(); } /** * 传进来了控制点坐标 * @param control_p */ public void ComputePoint(PointCom control_p,int Radius){ PointF Relative_p=new PointF(); Relative_p.x= control_p.x-x; Relative_p.y= control_p.y-y; float sinA= (float) (Relative_p.y/Math.sqrt( Relative_p.x*Relative_p.x+Relative_p.y*Relative_p.y)); float cosA= (float) (Relative_p.x/Math.sqrt(Relative_p.x*Relative_p.x+Relative_p.y*Relative_p.y)); right.x= Radius*sinA+x; right.y= Radius*cosA*-1+y; left.x = Radius*sinA*-1+x; left.y = Radius*cosA+y; } public PointCom(float x, float y) { this.x = x; this.y = y; left=new PointF(); right= new PointF(); } public PointF getLeft() { return left; } public void setLeft(PointF left) { this.left = left; } public PointF getRight() { return right; } public void setRight(PointF right) { this.right = right; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } } @Override public boolean onTouchEvent(MotionEvent event) { PointF point=new PointF(); point.x = event.getX(); point.y = event.getY(); int action=event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if (isRedPoint(point)) { isdown = true; downPoint.x = event.getX(); downPoint.y = event.getY(); return true; }else return false; case MotionEvent.ACTION_UP: status=3; invalidate(); break; case MotionEvent.ACTION_CANCEL: status=3; invalidate(); break; case MotionEvent.ACTION_MOVE: if (!isdown){ return super.onTouchEvent(event); } currentPoint.x=event.getX(); currentPoint.y=event.getY(); float distance = 0; distance=(downPoint.x-currentPoint.x)/normaldistance; switch ((int)distance){ case 0: status=1; invalidate(); break; case 1: status=1; invalidate(); break; default: status=2; invalidate(); break; } break; } return super.onTouchEvent(event); } /** * 判断是否是红点区域 */ public boolean isRedPoint(PointF point){ if( (point.x>centerX+100||point.x<centerX-100)&&(point.y<centerY-100||point.y>centerY+100 )) { return false; }else { int i=11; return true; } } }