利用贝塞尔函数仿QQ红点提示

45 篇文章 0 订阅

直接贴代码,不废话了

最主要的就是计算几个点的坐标问题,然后用二阶贝塞尔函数画出连接区域




用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;
        }
    }


}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值