畫個(gè)虛線箭頭連接引導(dǎo)2個(gè)View

需求

需要一個(gè)箭頭,連接1個(gè)View,指向(引導(dǎo))另一個(gè)View

實(shí)現(xiàn)方案

拿到這個(gè)需求我就在想,應(yīng)該如何實(shí)現(xiàn)會(huì)比較好。
考慮到Android平臺(tái)分辨率碎片化嚴(yán)重,單純的XML代碼估計(jì)很難實(shí)現(xiàn)。
于是想到用Canvas來畫。
實(shí)現(xiàn)思路比較簡單:

  1. 計(jì)算兩個(gè)View的起點(diǎn)和終點(diǎn)
  2. 通過貝塞爾曲線描繪一條彎曲的曲線
  3. 繪制一個(gè)倒三角形

計(jì)算兩個(gè)View的起點(diǎn)和終點(diǎn)

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 獲取到的坐標(biāo)是以屏幕左上角為原點(diǎn)計(jì)算的,所以真實(shí)的坐標(biāo)需要減去狀態(tài)欄以及ActionBar的高度(因?yàn)轫?xiàng)目沒有用到ActionBar,所以沒有減去這個(gè)高度)

通過貝塞爾曲線描繪一條彎曲的曲線

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 創(chuàng)建畫筆
        Paint p = new Paint();
        p.setColor(context.getResources().getColor(R.color.gray));  // 設(shè)置顏色
        p.setStrokeWidth(PixTool.dip2px(context, 1));   // 設(shè)置寬度
        p.setAntiAlias(true);   // 抗鋸齒

        // 設(shè)置虛線
        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: 這里的貝塞爾曲線的點(diǎn)需要一個(gè)優(yōu)化,當(dāng)終點(diǎn)y值小于起點(diǎn)y值得時(shí)候,需要再做一個(gè)處理。

繪制一個(gè)倒三角形

        float length = 32;  // 三角形的邊長
        float x = x2 - length / 2;
        p.setPathEffect(null); // 取消虛線效果
        p.setStyle(Paint.Style.FILL); //設(shè)置填滿

        // 畫三角形
        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);

實(shí)現(xiàn)效果

附上完整代碼 (代碼略渣,歡迎交流學(xué)習(xí))

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);

        // 創(chuàng)建畫筆
        Paint p = new Paint();
        p.setColor(context.getResources().getColor(R.color.gray));  // 設(shè)置顏色
        p.setStrokeWidth(PixTool.dip2px(context, 1));   // 設(shè)置寬度
        p.setAntiAlias(true);   // 抗鋸齒

        // 設(shè)置虛線
        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); //設(shè)置填滿

        // 畫三角形
        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);
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容