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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352