Android技术进阶Android DevAndroid进阶之路

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

2015-10-23  本文已影响520人  ONEWateR

需求

需要一个箭头,连接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);
    }

}
上一篇下一篇

猜你喜欢

热点阅读