美文网首页
Android 自定义View之圆角矩形轨迹图

Android 自定义View之圆角矩形轨迹图

作者: IT_lz | 来源:发表于2019-03-29 10:56 被阅读0次

    一、原理说明

    主要是通过计算轨迹的坐标点加入到集合中,然后对集合进行相应截取,传入canvas中。

    二、具体代码实现

    
    /**
     * 原理是先通过尺寸把各个轨迹的坐标计算出来,然后再截取相应坐标,进行重绘。
     *
     * @author lz
     * @Time 2019-3-27
     */
    public class RotateTrackView extends View {
    
        /**
         * 起始点横坐标
         */
        private float startXPoint;
    
        /**
         * 起始点纵坐标
         */
        private float startYPoint;
    
        /**
         * 宽度
         */
        private float width;
    
        /**
         * 高度
         */
        private float heigth;
    
        /**
         * 圆角半径
         */
        private float radius;
    
        /**
         * 图形点集合
         */
        float[] mPoints;
    
        /**
         * 画笔
         */
        private Paint mPaint;
    
        /**
         * 标志位
         */
        private final int LeftUp = 0;
        private final int LeftDown = 1;
        private final int RightDown = 2;
        private final int RightUp = 3;
    
        /**
         * 停止动画标志位
         */
        private boolean isPause = false;
    
        /**
         * 动画开始位置起点
         */
        private int indexBegin = 0;
        /**
         * 动画结束位置,也就是整个动画的长度
         */
        private int indexEnd = 200;
    
        private int LENGTH = 200;
    
        private int TIME = 1;
    
        /**
         * 截取的轨迹点集合
         */
        private float[] snackPoints;
    
        public RotateTrackView(Context context) {
            super(context);
        }
    
        public RotateTrackView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public RotateTrackView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public RotateTrackView(Context context, float startXPoint, float startYPoint, float width, float heigth, float radius) {
            this(context);
            this.startXPoint = startXPoint;
            this.startYPoint = startYPoint;
            this.heigth = heigth;
            this.width = width;
            this.radius = radius;
    
            // 初始化画笔
            mPaint = new Paint();
            mPaint.setColor(Color.RED);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(8);
    
            // 轨迹计算
            ArrayList<Float> mPointLists = new ArrayList<>();
            addXPoints(width, radius, startXPoint, startYPoint, mPointLists);
            addCircleArgle(RightUp, radius, mPointLists);
            addYPoints(heigth, radius, mPointLists.get(mPointLists.size() - 1), mPointLists.get(mPointLists.size() - 2), mPointLists);
            addCircleArgle(RightDown, radius, mPointLists);
            reduceXPoints(width, radius, mPointLists.get(mPointLists.size() - 2), mPointLists.get(mPointLists.size() - 1), mPointLists);
            addCircleArgle(LeftDown, radius, mPointLists);
            reduceYPoints(heigth, radius, mPointLists.get(mPointLists.size() - 1), mPointLists.get(mPointLists.size() - 2), mPointLists);
            addCircleArgle(LeftUp, radius, mPointLists);
    
            // 将list集合转换成canvas接受的float数组
            mPoints = new float[mPointLists.size()];
            for (int i = 0; i < mPointLists.size(); i++) {
                mPoints[i] = mPointLists.get(i);
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (snackPoints.length == LENGTH) {
                canvas.drawPoints(snackPoints, mPaint);
            }
        }
    
        /**
         * x轴向右计算
         *
         * @param length
         * @param radius
         * @param addNumber
         * @param constantNumber
         * @param list
         */
        private void addXPoints(float length, float radius, float addNumber, float constantNumber, List<Float> list) {
            for (int i = 1; i < (length - 2 * radius); i++) {
                float pointX = addNumber + i;
                float pointY = constantNumber;
                list.add(pointX);
                list.add(pointY);
            }
        }
    
        private void reduceXPoints(float length, float radius, float addNumber, float constantNumber, List<Float> list) {
            for (int i = 1; i < (length - 2 * radius); i++) {
                float pointX = addNumber - i;
                float pointY = constantNumber;
                list.add(pointX);
                list.add(pointY);
            }
        }
    
        private void addYPoints(float length, float radius, float addNumber, float constantNumber, List<Float> list) {
            for (int i = 1; i < (length - 2 * radius); i++) {
                float pointX = addNumber + i;
                float pointY = constantNumber;
                list.add(pointY);
                list.add(pointX);
            }
        }
    
        private void reduceYPoints(float length, float radius, float addNumber, float constantNumber, List<Float> list) {
            for (int i = 1; i < (length - 2 * radius); i++) {
                float pointX = addNumber - i;
                float pointY = constantNumber;
                list.add(pointY);
                list.add(pointX);
            }
        }
    
        /**
         * 由于上下左右四个圆的轨迹坐标计算方式是不一样的,需要单独处理
         *
         * @param position
         * @param radius
         * @param list
         */
        private void addCircleArgle(int position, float radius, List<Float> list) {
            int argle = 0;
            float x = list.get(list.size() - 2);
            float y = list.get(list.size() - 1);
            for (int i = 0; i < 90; i += 10) {
                argle = i + 10;
    
                switch (position) {
    
                    case RightUp:
                        float x1 = (float) (x + Math.sin((Math.PI / 180) * argle) * radius);
                        float y1 = (float) (y + (radius - Math.cos((Math.PI / 180) * argle) * radius));
                        list.add(x1);
                        list.add(y1);
                        break;
    
                    case RightDown:
                        float x2 = (float) (x - (radius - Math.cos((Math.PI / 180) * argle) * radius));
                        float y2 = (float) (y + (Math.sin((Math.PI / 180) * argle) * radius));
                        list.add(x2);
                        list.add(y2);
                        break;
    
                    case LeftDown:
                        float x3 = (float) (x - (Math.sin((Math.PI / 180) * argle) * radius));
                        float y3 = (float) (y - (radius - Math.cos((Math.PI / 180) * argle) * radius));
                        list.add(x3);
                        list.add(y3);
                        break;
    
                    case LeftUp:
                        float x4 = (float) (x + (radius - Math.cos((Math.PI / 180) * argle) * radius));
                        float y4 = (float) (y - (Math.sin((Math.PI / 180) * argle) * radius));
                        list.add((float) (x + (radius - Math.cos((Math.PI / 180) * argle) * radius)));
                        list.add((float) (y - (Math.sin((Math.PI / 180) * argle) * radius)));
                        break;
    
                    default:
                        break;
                }
            }
        }
    
        /**
         * 开始动画
         */
        public void startAnim() {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    super.run();
                    while (!isPause) {
                        RotateTrackView.this.post(new Runnable() {
                            @Override
                            public void run() {
                                invalidate();
                            }
                        });
                        indexBegin += 2;
                        indexEnd += 2;
                        if (indexEnd < mPoints.length) {
                            snackPoints = (Arrays.copyOfRange(mPoints, indexBegin, indexEnd));
                        } else if (indexBegin == mPoints.length) {
                            indexBegin = 0;
                            indexEnd = LENGTH;
                        } else {
                            float[] floats2 = Arrays.copyOfRange(mPoints, indexBegin, mPoints.length);
                            float[] floats3 = Arrays.copyOf(floats2, LENGTH);
                            int length = floats2.length;
                            for (int i = 0; i < (LENGTH - floats2.length); i++) {
                                floats3[length] = mPoints[i];
                                length++;
                            }
                            snackPoints = floats3;
    
                        }
                        try {
                            Thread.sleep(TIME);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            thread.start();
        }
    
        /**
         * 停止动画
         */
        public void stopAnim() {
            isPause = true;
        }
    
        /**
         * 设置轨迹粗细
         */
        public void setLinesWidth(int width) {
            mPaint.setStrokeWidth(width);
        }
    }
    

    三、使用方法

    public class MainActivity extends AppCompatActivity {
    
        private RotateTrackView rotateTrackView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // 创建RotateTrackView, 设置起始坐标、宽、高、圆角半径
            rotateTrackView = new RotateTrackView(this, 500, 600, 250, 180, 30);
            setContentView(rotateTrackView);
            // 设置画笔粗细
            rotateTrackView.setLinesWidth(20);
            // 开始动画
            rotateTrackView.startAnim();
        }
    }
    

    四、效果展示

    RotateTrackView.gif

    五、下载地址

    https://github.com/liuzheng1101/RotateTrackView

    相关文章

      网友评论

          本文标题:Android 自定义View之圆角矩形轨迹图

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