• 需求:随着手指滑动,出现一个指示用的箭头,向这样的

    画一条线很简单,用onTouchEvent()即可,难点在画那个小箭头上面,看着简单,画起来各种角度、坐标系,画的欲仙欲死的···

    1. 首先确定2个点的位置,并传给自定义控件arrowView

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
          private ArrowView av;
      private float startX;
      private float startY;
      @Override
      public boolean onTouchEvent(MotionEvent event) {
      int action = event.getAction();
      switch (action) {
      case MotionEvent.ACTION_DOWN:
      //记下按下去的初始位置,actionbarHeight和statusHeight是toolBar和状态栏的高度
      startX = event.getX();
      startY = event.getY()-actionBarHeight-statusHeight;
      break;
      case MotionEvent.ACTION_MOVE:
      float moveX = event.getX();
      float moveY = event.getY()-actionBarHeight-statusHeight;
      av.clear(); //每次移动的时候都先清空一次path
      av.setPath(startX,startY,moveX,moveY); //将2个点的位置传给arrowView
      break;
      case MotionEvent.ACTION_UP:
      //do something
      }
      break;
      }
      return super.onTouchEvent(event);
      }
      1. ArrowView来了

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        package com.aidebar.intentdemo;

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

        /**
        * @author xzj
        * @date 2016/10/26 14:59.
        */

        public class ArrowView extends View {
        private Paint paint;
        private Path path;
        private Paint arrowPaint;
        private Path arrowPath;
        private float startX;
        private float startY;
        private float endX;
        private float endY;

        public ArrowView(Context context) {
        super(context);
        init();
        }

        public ArrowView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        }

        public ArrowView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
        }

        private void init() {
        paint = new Paint();
        arrowPaint = new Paint();
        arrowPaint.setAntiAlias(true);
        arrowPaint.setColor(Color.RED);
        arrowPaint.setStrokeWidth(5);
        arrowPaint.setStyle(Paint.Style.FILL);//箭头是个实心三角形,所以用fill
        arrowPath = new Path();
        path = new Path();
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
        }

        @Override
        protected void onDraw(Canvas canvas) {
        setArrowPath();
        canvas.drawPath(path, paint);
        canvas.drawPath(arrowPath, arrowPaint);
        }

        /**
        * 画箭头
        */
        public void setArrowPath() {
        double H = 18; // 箭头高度
        double L = 13.5; // 底边的一半

        double angle = Math.atan(L / H); // 箭头角度
        double arrowLength = Math.sqrt(L * L + H * H); // 箭头的长度
        //箭头就是个三角形,我们已经有一个点了,根据箭头的角度和长度,确定另外2个点的位置
        double[] point1 = rotateVec(endX - startX, endY - startY, angle, arrowLength);
        double[] point2 = rotateVec(endX - startX, endY - startY, -angle, arrowLength);
        double point1_x = endX - point1[0];
        double point1_y = endY - point1[1];
        double point2_x = endX - point2[0];
        double point2_y = endY - point2[1];
        int x3 = (int) point1_x;
        int y3 = (int) point1_y;
        int x4 = (int) point2_x;
        int y4 = (int) point2_y;
        // 画线
        arrowPath.moveTo(endX, endY);
        arrowPath.lineTo(x3, y3);
        arrowPath.lineTo(x4, y4);
        arrowPath.close();
        }
        // 计算
        /**
        * @param diffX X的差值
        * @param diffY Y的差值
        * @param angle 箭头的角度(箭头三角形的线与直线的角度)
        * @param arrowLength 箭头的长度
        */
        public double[] rotateVec(float diffX, float diffY, double angle, double arrowLength) {
        double arr[] = new double[2];
        // 下面的是公式,得出的是以滑动出的线段末点为中心点旋转angle角度后,线段起点的坐标,这个旋转后的线段也就是“变长了的箭头的三角形的一条边”
        //推导见注释1
        double x = diffX * Math.cos(angle) - diffY * Math.sin(angle);
        double y = diffX * Math.sin(angle) + diffY * Math.cos(angle);
        double d = Math.sqrt(x * x + y * y);
        //根据相似三角形,得出真正的箭头三角形顶点坐标,这里见注释2
        x = x / d * arrowLength;
        y = y / d * arrowLength;
        arr[0] = x;
        arr[1] = y;
        return arr;
        }
        public void setPath(float startX, float startY, float endX, float endY) {
        path.moveTo(startX,startY);
        path.lineTo(endX,endY);
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        invalidate();
        }
        public void clear() {
        path.reset();
        arrowPath.reset();
        }
        }

        注释1:前方高能,初中数学老师来临

        一个点坐标为(x1,y1),与x轴夹角为A,与原点距离为r,那么

        x1 = r *cosA ————–①

        y1 = r *sinA ————–②

        以原点为圆心,将该点旋转B度后,得到点(x2,y2)
        x2 = r *cos(A+B)= r *(cosAcosB - sinAsinB)
        y2 = r *sin(A+B)= r *(sinAcosB + cosAsinB)
        将①②式带入可得:
        x2 = x1cosB - y1sinB
        y2 = y1cosB + x1sinB

        注释2:前方高能,初中数学老师又来了

        x/x1=arrowLength/d
        x = x1 / d * arrowLength

        EOF