如何实现一个可拖拽的圆并且可以改变大小

layout: post

title: '如何实现一个可拖拽的圆并且可以改变大小'

subtitle: '转载请注明出处'

date: 2019-08-12

categories: Android View 自定义View

cover: 'http://bpic.588ku.com/back_pic/05/61/11/465b46e23671e61.jpg'

tags: Android View


untitled.gif


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;



public class DragCircle extends View {

    private static final float POINT_RADIUS = 10; // dp,锚点绘制半价
    private static final float TOUCH_POINT_CATCH_DISTANCE = 15; //dp,触摸点捕捉到锚点的最小距离
    private static final int DEFAULT_LINE_COLOR = Color.parseColor("#F33737");
    private float mDensity;
    private PointF[] points; //点
    float mLineWidth = 1.0f; // 选区线的宽度
    int mLineColor = DEFAULT_LINE_COLOR; // 选区线的颜色
    private Path mPointLinePath = new Path();
    private Paint mLinePaint;
    private PointF mDraggingPoint = null;


    public DragCircle(Context context) {
        super(context);
    }

    public DragCircle(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mDensity = getResources().getDisplayMetrics().density;
        initPaints();
        initPoints();
    }

    public DragCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    private void initPaints() {
        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mLinePaint.setColor(mLineColor);
        mLinePaint.setStrokeWidth(mLineWidth);
        mLinePaint.setStyle(Paint.Style.STROKE);
    }

    private void initPoints() {
        PointF[] points = new PointF[3];
        points[0] = new PointF(-50, -50);
        points[1] = new PointF(-50, -50);
        points[2] = new PointF(-50, -50);
        this.points = points;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制线
        onDrawLines(canvas);
        //绘制锚点
        onDrawPoints(canvas);
        //绘制圆
        onDrawCircle(canvas);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        boolean handle = true;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mDraggingPoint = getNearbyPoint(event);
                if (mDraggingPoint == null) {
                    points[0].x = event.getX();
                    points[0].y = event.getY();
                    points[1].x = event.getX();
                    points[1].y = event.getY();
                    mDraggingPoint = getNearbyPoint(event);
                    handle = true; //返回true 触发手势
                }

                break;
            case MotionEvent.ACTION_MOVE:
                toImagePointSize(mDraggingPoint, event);
                break;
            case MotionEvent.ACTION_UP:
                mDraggingPoint = null;
                break;
        }
        invalidate();
        return handle || super.onTouchEvent(event);
    }


    private void toImagePointSize(PointF dragPoint, MotionEvent event) {
        if (dragPoint == null) {
            return;
        }

        PlottingScale.DragPointType pointType = getPointType(dragPoint);

        int x = (int) event.getX();
        int y = (int) event.getY();

        if (pointType != null) {
            switch (pointType) {
                case LEFT:
                    dragPoint.y = y;
                    dragPoint.x = x;

                    points[2].x = (points[0].x + points[1].x) / 2;
                    points[2].y = (points[0].y + points[1].y) / 2;

                    break;
                case RIGHT:
                    dragPoint.y = y;
                    dragPoint.x = x;

                    points[2].x = (points[0].x + points[1].x) / 2;
                    points[2].y = (points[0].y + points[1].y) / 2;

                    break;

                case CENTER:
                    points[0].x = points[0].x + (x - dragPoint.x);
                    points[0].y = points[0].y + (y - dragPoint.y);
                    points[1].x = points[1].x + (x - dragPoint.x);
                    points[1].y = points[1].y + (y - dragPoint.y);
                    dragPoint.y = y;
                    dragPoint.x = x;
                    break;
                default:
                    break;
            }
        }

    }

    private PlottingScale.DragPointType getPointType(PointF dragPoint) {
        if (dragPoint == null) return null;

        PlottingScale.DragPointType type;
        if (checkPoints(points)) {
            for (int i = 0; i < points.length; i++) {
                if (dragPoint == points[i]) {
                    type = PlottingScale.DragPointType.values()[i];
                    return type;
                }
            }
        }

        return null;
    }

    private PointF getNearbyPoint(MotionEvent event) {
        if (checkPoints(points)) {
            for (PointF p : points) {
                if (isTouchPoint(p, event)) return p;
            }
        }
        return null;
    }

    private boolean isTouchPoint(PointF p, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        float px = p.x;
        float py = p.y;
        double distance = Math.sqrt(Math.pow(x - px, 2) + Math.pow(y - py, 2));
        if (p == points[2]) {
            if (distance < (MathUtils.getDistance(points[0], points[1]) / 2.0)) {
                return true;
            }
        }
        if (distance < dp2px(TOUCH_POINT_CATCH_DISTANCE)) {
            return true;
        }
        return false;
    }

    protected void onDrawLines(Canvas canvas) {
        Path path = resetPointPath();
        if (path != null) {
            canvas.drawPath(path, mLinePaint);
        }
    }


    protected void onDrawPoints(Canvas canvas) {
        if (!checkPoints(points)) {
            return;
        }
        for (int i = 0; i < points.length; i++) {
            PointF point = points[i];
            if (i != points.length - 1) {
                canvas.drawCircle(point.x, point.y, dp2px(POINT_RADIUS), mLinePaint);
            }
        }
//        for (PointF point : points) {
//            canvas.drawCircle(point.x, point.y, dp2px(POINT_RADIUS), mLinePaint);
//        }
    }


    protected void onDrawCircle(Canvas canvas) {
        if (!checkPoints(points)) {
            return;
        }

        float radus = (float) (MathUtils.getDistance(points[0], points[1]) / 2.0);
        canvas.drawCircle(points[2].x, points[2].y, radus, mLinePaint);
    }


    public boolean checkPoints(PointF[] points) {
        return points != null && points.length == 3
                && points[0] != null && points[1] != null && points[2] != null;
    }


    private Path resetPointPath() {
        if (!checkPoints(points)) {
            return null;
        }

        mPointLinePath.reset();
        PointF p0 = points[0];
        PointF p1 = points[1];
        PointF p2 = points[2];

        mPointLinePath.moveTo(p0.x, p0.y);
        mPointLinePath.lineTo(p1.x, p1.y);
        mPointLinePath.moveTo(p2.x, p2.y);
        return mPointLinePath;
    }

    private float dp2px(float dp) {
        return dp * mDensity;
    }

    enum DragPointType {
        LEFT,
        RIGHT,
        CENTER
    }
}

涉及到的工具类MathUtils

你可能感兴趣的:(如何实现一个可拖拽的圆并且可以改变大小)