画个虚线箭头连接引导2个View

作者: ONEWateR | 来源:发表于2015-10-23 20:01 被阅读520次

    需求

    需要一个箭头,连接1个View,指向(引导)另一个View

    实现方案

    拿到这个需求我就在想,应该如何实现会比较好。
    考虑到Android平台分辨率碎片化严重,单纯的XML代码估计很难实现。
    于是想到用Canvas来画。
    实现思路比较简单:

    1. 计算两个View的起点和终点
    2. 通过贝塞尔曲线描绘一条弯曲的曲线
    3. 绘制一个倒三角形

    计算两个View的起点和终点

    int[] location = new int[2];
    startView.getLocationInWindow(location);
    
    x1 = location[0];
    y1 = location[1] - PixTool.getStatusBarHeight(context) + startView.getHeight() / 2;
    
    endView.getLocationInWindow(location);
    
    x2 = location[0] + endView.getWidth() / 2;
    y2 = location[1] - PixTool.getStatusBarHeight(context) - 53;
    

    Note: 这里的 getLocationInWindow 获取到的坐标是以屏幕左上角为原点计算的,所以真实的坐标需要减去状态栏以及ActionBar的高度(因为项目没有用到ActionBar,所以没有减去这个高度)

    通过贝塞尔曲线描绘一条弯曲的曲线

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            // 创建画笔
            Paint p = new Paint();
            p.setColor(context.getResources().getColor(R.color.gray));  // 设置颜色
            p.setStrokeWidth(PixTool.dip2px(context, 1));   // 设置宽度
            p.setAntiAlias(true);   // 抗锯齿
    
            // 设置虚线
            PathEffect effects = new DashPathEffect(new float[]{PixTool.dip2px(context, 6), PixTool.dip2px(context, 3)}, 1);
            p.setPathEffect(effects);
    
            //画贝塞尔曲线
            p.setStyle(Paint.Style.STROKE);
            Path path2 = new Path();
            path2.moveTo(x1, y1);
    
            float quaX = x1 / 4;
            float quaY = (y1 + y2) / 2;
            if (y2 - y1 < 0) {
                quaX = (x1 + x2) / 2;
                quaY = y2 - 100;
            }else if (y2 - y1 < 50){
                quaX = (x1 + x2) / 2;
                quaY = y1 - 50;
            }
            path2.quadTo(quaX, quaY, x2, y2);
            canvas.drawPath(path2, p);
        }
    
    

    Note: 这里的贝塞尔曲线的点需要一个优化,当终点y值小于起点y值得时候,需要再做一个处理。

    绘制一个倒三角形

            float length = 32;  // 三角形的边长
            float x = x2 - length / 2;
            p.setPathEffect(null); // 取消虚线效果
            p.setStyle(Paint.Style.FILL); //设置填满
    
            // 画三角形
            Path path = new Path();
            path.moveTo(x, y2);
            path.lineTo(x + length, y2);
            path.lineTo((x + x + length) / 2, y2 + 23);
            path.close();
    
            canvas.drawPath(path, p);
    

    实现效果

    附上完整代码 (代码略渣,欢迎交流学习)

    public class DashArrow extends View {
    
        Context context;
    
        float x1 = 0;
        float y1 = 0;
    
        float x2 = 0;
        float y2 = 0;
    
        public DashArrow(Context context, float x1, float y1, float x2, float y2) {
            super(context);
            this.context = context;
    
            this.x1 = x1;
            this.y1 = y1;
    
            this.x2 = x2;
            this.y2 = y2;
        }
    
        public DashArrow(Context context, View startView, View endView) {
            super(context);
            this.context = context;
    
            int[] location = new int[2];
            startView.getLocationInWindow(location);
    
            x1 = location[0];
            y1 = location[1] - PixTool.getStatusBarHeight(context) + startView.getHeight() / 2;
    
            endView.getLocationInWindow(location);
    
            x2 = location[0] + endView.getWidth() / 2;
            y2 = location[1] - PixTool.getStatusBarHeight(context) - 53;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            // 创建画笔
            Paint p = new Paint();
            p.setColor(context.getResources().getColor(R.color.gray));  // 设置颜色
            p.setStrokeWidth(PixTool.dip2px(context, 1));   // 设置宽度
            p.setAntiAlias(true);   // 抗锯齿
    
            // 设置虚线
            PathEffect effects = new DashPathEffect(new float[]{PixTool.dip2px(context, 6), PixTool.dip2px(context, 3)}, 1);
            p.setPathEffect(effects);
    
            //画贝塞尔曲线
            p.setStyle(Paint.Style.STROKE);
            Path path2 = new Path();
            path2.moveTo(x1, y1);
    
            float quaX = x1 / 4;
            float quaY = (y1 + y2) / 2;
            if (y2 - y1 < 0) {
                quaX = (x1 + x2) / 2;
                quaY = y2 - 100;
            }else if (y2 - y1 < 50){
                quaX = (x1 + x2) / 2;
                quaY = y1 - 50;
            }
            path2.quadTo(quaX, quaY, x2, y2);
    
            canvas.drawPath(path2, p);
    
            float length = 32;  // 三角形的边长
            float x = x2 - length / 2;
            p.setPathEffect(null); // 取消虚线效果
            p.setStyle(Paint.Style.FILL); //设置填满
    
            // 画三角形
            Path path = new Path();
            path.moveTo(x, y2);
            path.lineTo(x + length, y2);
            path.lineTo((x + x + length) / 2, y2 + 23);
            path.close();
    
            canvas.drawPath(path, p);
        }
    
    }
    

    相关文章

      网友评论

        本文标题:画个虚线箭头连接引导2个View

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