美文网首页
如何实现一个可拖拽的H线

如何实现一个可拖拽的H线

作者: galaxy_zheng | 来源:发表于2019-08-13 16:42 被阅读0次

    layout: post

    title: '如何实现一个可拖拽的H线'

    subtitle: '转载请注明出处'

    date: 2019-08-13

    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 HLine 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;
    
        private double angle;
        private double distance;
        private double angle_p0p3;
        private double angle_p3p0;
        private double distance_p0p3;
    
        public HLine(Context context) {
            super(context);
        }
    
        public HLine(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public HLine(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mDensity = getResources().getDisplayMetrics().density;
            initPaints();
        }
    
        private void initPaints() {
            mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mLinePaint.setColor(mLineColor);
            mLinePaint.setStrokeWidth(mLineWidth);
            mLinePaint.setStyle(Paint.Style.STROKE);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            initPoints();
        }
    
        private void initPoints() {
            PointF[] points = new PointF[6];
            points[0] = new PointF(getWidth() / 5 * 2, getHeight() / 6 * 1);
            points[1] = new PointF(getWidth() / 5 * 2, getHeight() / 6 * 3);
            points[2] = new PointF(getWidth() / 5 * 2, getHeight() / 6 * 5);
            points[3] = new PointF(getWidth() / 5 * 3, getHeight() / 6 * 1);
            points[4] = new PointF(getWidth() / 5 * 3, getHeight() / 6 * 3);
            points[5] = new PointF(getWidth() / 5 * 3, getHeight() / 6 * 5);
            this.points = points;
    
            distance_p0p3 = MathUtils.getDistance(points[0], points[3]);
            angle_p0p3 = MathUtils.getAngleFromPoint(points[0], points[3]);
            angle_p3p0 = MathUtils.getAngleFromPoint(points[3], points[0]);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.BLACK);
            //绘制线
            onDrawLines(canvas);
            //绘制锚点
            onDrawPoints(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) {
                        handle = false;
                    }
    
                    break;
                case MotionEvent.ACTION_MOVE:
                    toImagePointSize(mDraggingPoint, event);
                    break;
                case MotionEvent.ACTION_UP:
                    mDraggingPoint = null;
                    break;
            }
            invalidate();
            return handle || super.onTouchEvent(event);
        }
    
    
        private static final String TAG = "HPlanningLine";
    
        private void toImagePointSize(PointF dragPoint, MotionEvent event) {
            if (dragPoint == null) {
                return;
            }
    
            DragPointType pointType = getPointType(dragPoint);
    
            float x = event.getX();
            float y = event.getY() <= 0 ? 0 : event.getY();
    
            if (pointType != null) {
                switch (pointType) {
    
                    case LEFT_TOP:
                        if (!canMoveLeftTop(x, y)) return;
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[2], points[0]);
                        distance = MathUtils.getDistance(points[1], points[2]);
                        points[1].x = (float) (points[2].x + distance * Math.cos(Math.toRadians(angle)));
                        points[1].y = (float) (points[2].y + distance * Math.sin(Math.toRadians(angle)));
                        angle = MathUtils.getAngleFromPoint(points[2], points[0]) - 270;
                        points[3].x = (float) (points[0].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[3].y = (float) (points[0].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[4].x = (float) (points[1].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[4].y = (float) (points[1].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[5].x = (float) (points[2].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[5].y = (float) (points[2].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
    
                        break;
                    case LEFT_MID:
    
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[5], points[3]) - 270;
                        distance_p0p3 = MathUtils.getDistance(points[1], points[4]);
                        points[0].x = (float) (points[3].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p3p0 + angle)));
                        points[0].y = (float) (points[3].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p3p0 + angle)));
                        points[2].x = (float) (points[5].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p3p0 + angle)));
                        points[2].y = (float) (points[5].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p3p0 + angle)));
    
                        angle = MathUtils.getAngleFromPoint(points[0], points[2]);
                        distance = MathUtils.getDistance(points[0], points[1]);
                        points[1].x = (float) (points[0].x + distance * Math.cos(Math.toRadians(angle)));
                        points[1].y = (float) (points[0].y + distance * Math.sin(Math.toRadians(angle)));
                        points[4].x = (float) (points[3].x + distance * Math.cos(Math.toRadians(angle)));
                        points[4].y = (float) (points[3].y + distance * Math.sin(Math.toRadians(angle)));
    
    
                        break;
                    case LEFT_BOTTOM:
                        if (!canMoveLeftBottom(x, y)) return;
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[0], points[2]);
                        distance = MathUtils.getDistance(points[1], points[0]);
                        points[1].x = (float) (points[0].x + distance * Math.cos(Math.toRadians(angle)));
                        points[1].y = (float) (points[0].y + distance * Math.sin(Math.toRadians(angle)));
                        angle = MathUtils.getAngleFromPoint(points[2], points[0]) - 270;
                        points[3].x = (float) (points[0].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[3].y = (float) (points[0].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[4].x = (float) (points[1].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[4].y = (float) (points[1].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[5].x = (float) (points[2].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[5].y = (float) (points[2].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        break;
    
                    case RIGHT_TOP:
                        if (!canMoveRightTop(x, y)) return;
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[5], points[3]);
                        distance = MathUtils.getDistance(points[4], points[5]);
                        points[4].x = (float) (points[5].x + distance * Math.cos(Math.toRadians(angle)));
                        points[4].y = (float) (points[5].y + distance * Math.sin(Math.toRadians(angle)));
                        angle = MathUtils.getAngleFromPoint(points[5], points[3]) - 270;
                        points[0].x = (float) (points[3].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p3p0 + angle)));
                        points[0].y = (float) (points[3].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p3p0 + angle)));
                        points[1].x = (float) (points[4].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p3p0 + angle)));
                        points[1].y = (float) (points[4].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p3p0 + angle)));
                        points[2].x = (float) (points[5].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p3p0 + angle)));
                        points[2].y = (float) (points[5].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p3p0 + angle)));
    
                        break;
                    case RIGHT_MID:
    
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[2], points[0]) - 270;
                        distance_p0p3 = MathUtils.getDistance(points[1], points[4]);
                        points[3].x = (float) (points[0].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[3].y = (float) (points[0].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[5].x = (float) (points[2].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[5].y = (float) (points[2].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
    
                        angle = MathUtils.getAngleFromPoint(points[3], points[5]);
                        distance = MathUtils.getDistance(points[3], points[4]);
                        points[1].x = (float) (points[0].x + distance * Math.cos(Math.toRadians(angle)));
                        points[1].y = (float) (points[0].y + distance * Math.sin(Math.toRadians(angle)));
                        points[4].x = (float) (points[3].x + distance * Math.cos(Math.toRadians(angle)));
                        points[4].y = (float) (points[3].y + distance * Math.sin(Math.toRadians(angle)));
    
                        break;
                    case RIGHT_BOTTOM:
                        if (!canMoveRightBottom(x, y)) return;
    
                        dragPoint.y = y;
                        dragPoint.x = x;
                        angle = MathUtils.getAngleFromPoint(points[3], points[5]);
                        distance = MathUtils.getDistance(points[4], points[3]);
                        points[4].x = (float) (points[3].x + distance * Math.cos(Math.toRadians(angle)));
                        points[4].y = (float) (points[3].y + distance * Math.sin(Math.toRadians(angle)));
                        angle = MathUtils.getAngleFromPoint(points[3], points[5]) - 270;
                        points[0].x = (float) (points[3].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[0].y = (float) (points[3].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[1].x = (float) (points[4].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[1].y = (float) (points[4].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        points[2].x = (float) (points[5].x + distance_p0p3 * Math.cos(Math.toRadians(angle_p0p3 + angle)));
                        points[2].y = (float) (points[5].y + distance_p0p3 * Math.sin(Math.toRadians(angle_p0p3 + angle)));
                        break;
                    default:
                        break;
                }
            }
    
        }
    
    
        private boolean canMoveLeftTop(float x, float y) {
            if (MathUtils.getDistance(x, y, points[2].x, points[2].y) - MathUtils.getDistance(points[1], points[2]) - 2 * dp2px(POINT_RADIUS) <= 0) {
                return false;
            }
            return true;
        }
    
        private boolean canMoveLeftBottom(float x, float y) {
            if (MathUtils.getDistance(x, y, points[0].x, points[0].y) - MathUtils.getDistance(points[1], points[0]) - 2 * dp2px(POINT_RADIUS) <= 0) {
                return false;
            }
            return true;
        }
    
        private boolean canMoveRightTop(float x, float y) {
            if (MathUtils.getDistance(x, y, points[5].x, points[5].y) - MathUtils.getDistance(points[4], points[5]) - 2 * dp2px(POINT_RADIUS) <= 0) {
                return false;
            }
            return true;
        }
    
        private boolean canMoveRightBottom(float x, float y) {
            if (MathUtils.getDistance(x, y, points[3].x, points[3].y) - MathUtils.getDistance(points[4], points[3]) - 2 * dp2px(POINT_RADIUS) <= 0) {
                return false;
            }
            return true;
        }
    
        private DragPointType getPointType(PointF dragPoint) {
            if (dragPoint == null) return null;
    
            DragPointType type;
            if (checkPoints(points)) {
                for (int i = 0; i < points.length; i++) {
                    if (dragPoint == points[i]) {
                        type = 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 (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 (PointF point : points) {
                canvas.drawCircle(point.x, point.y, dp2px(POINT_RADIUS), mLinePaint);
            }
        }
    
    
        public boolean checkPoints(PointF[] points) {
            return points != null && points.length == 6
                    && points[0] != null && points[1] != null && points[2] != null && points[3] != null && points[4] != null && points[5] != null;
        }
    
    
        private Path resetPointPath() {
            if (!checkPoints(points)) {
                return null;
            }
    
            mPointLinePath.reset();
            PointF p0 = points[0];
            PointF p1 = points[1];
            PointF p2 = points[2];
            PointF p3 = points[3];
            PointF p4 = points[4];
            PointF p5 = points[5];
    
            mPointLinePath.moveTo(p0.x, p0.y);
            mPointLinePath.lineTo(p2.x, p2.y);
    
            mPointLinePath.moveTo(p3.x, p3.y);
            mPointLinePath.lineTo(p5.x, p5.y);
    
            mPointLinePath.moveTo(p1.x, p1.y);
            mPointLinePath.lineTo(p4.x, p4.y);
    
            return mPointLinePath;
        }
    
        private float dp2px(float dp) {
            return dp * mDensity;
        }
    
        enum DragPointType {
            LEFT_TOP,
            LEFT_MID,
            LEFT_BOTTOM,
            RIGHT_TOP,
            RIGHT_MID,
            RIGHT_BOTTOM,
    
        }
    }
    

    涉及到的工具类MathUtils

    相关文章

      网友评论

          本文标题:如何实现一个可拖拽的H线

          本文链接:https://www.haomeiwen.com/subject/ceebjctx.html