Android 动态关系图

1、先上一个效果图:

2、最近做了一个类似企查查的关系图,要求是绘制人物节点,节点之间关系标示,布局可缩放,单个节点可拖动。需求背景交代完毕。

3、简单说一下思路,自定义View ,继承SurfaceView,这种设计不会影响主线程的操作,surfaceView拥有独立的Cavans,绘制效率高,动画效果流畅。

4、开始上代码

      第一步,画圆,这个简单,需要的是外部传入节点的信息,xy位置及半径大小。这个不难,需要注意的是节点内部的文字需要做调整,保证文字在圆心位置,至少看起来是。


    //关系图 圆形
    private void drawCircle(Canvas canvas, int radius, int positionX, int positionY, int circleColor, int fillColor, String text, int textColor, int textSize) {
        mPaint.setColor(circleColor);
        canvas.drawCircle(positionX, positionY, radius, mPaint);
        mPaint.setColor(fillColor);
        canvas.drawCircle(positionX, positionY, radius - 1, mPaint);

        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(textColor);


        mPaint.setTextSize(textSize);

        positionY += 5;
        if (text.length() > 0 && text.length() <= 5) {
            canvas.drawText(text, positionX, positionY, mPaint);
        } else if (text.length() > 5 && text.length() <= 10) {
            canvas.drawText(text.substring(0, 3), positionX, positionY - 25, mPaint);
            canvas.drawText(text.substring(3, text.length()), positionX, positionY, mPaint);
        } else if (text.length() > 10 && text.length() <= 15) {
            canvas.drawText(text.substring(0, 3), positionX, positionY - 25, mPaint);
            canvas.drawText(text.substring(3, 8), positionX, positionY, mPaint);
            canvas.drawText(text.substring(8, text.length()), positionX, positionY + 25, mPaint);
        } else if (text.length() > 15) {
            canvas.drawText(text.substring(0, 3), positionX, positionY - 50, mPaint);
            canvas.drawText(text.substring(3, 8), positionX, positionY - 25, mPaint);
            canvas.drawText(text.substring(8, 14), positionX, positionY, mPaint);
            canvas.drawText(text.substring(14, text.length()), positionX, positionY + 25, mPaint);
        }
        canvas.save();
        mPaint.reset();
    }

第二步,画节点与节点间的连线,这里有个问题就是,知道两个圆心的位置,节点半径,但是需要计算连线与节点圆的交点位置。

    private void caculate(int startX, int startY, int r1, int endX, int endY, int r2, String text, int textColor, int lineColor, int textSize) {

        double h = Math.abs(endY - startY);
        double w = Math.abs(endX - startX);

        double degree = Math.toDegrees(Math.atan(w / h));

//        Log.d(TAG, "CACULATE -- degree " + degree + "  " + (r1 * Math.sin(Math.PI / 180 * 30)));
        int x11 = 0, y11 = 0, x22 = 0, y22 = 0;
        if (startX > endX) {
            x11 = (int) (startX - (r1 * Math.sin(Math.PI / 180 * degree)));
            x22 = (int) (endX + (r2 * Math.sin(Math.PI / 180 * degree)));
        } else {
            x11 = (int) (startX + (r1 * Math.sin(Math.PI / 180 * degree)));
            x22 = (int) (endX - (r2 * Math.sin(Math.PI / 180 * degree)));
        }

        if (startY < endY) {
            y11 = (int) (startY + (r1 * Math.cos(Math.PI / 180 * degree)));
            y22 = (int) (endY - (r2 * Math.cos(Math.PI / 180 * degree)));
        } else {
            y11 = (int) (startY - (r1 * Math.cos(Math.PI / 180 * degree)));
            y22 = (int) (endY + (r2 * Math.cos(Math.PI / 180 * degree)));
        }
        drawAL(canvas, x11, y11, x22 - 3, y22 - 3, text, textColor, lineColor, textSize);
    }

我给画个草图,帮助理解 ,这就是三角形的部分知识,不懂的同学问问初中的表弟,Math类包含很多计算方法,思路就是求出一个角度,算出两圆心连线与各节点的交点位置,这里看看代码,不再赘述。

第三步,画箭头,这个不难,可以去百度找找,很多类似代码,根据需求改吧改吧。晚点我会上这个View的整体代码,这里就不贴了。

 到这里,基本的绘制工作完成,不难,接下来确定三个方法,

  1、画布随手指拖动

   这个问题处理的方法是,确定好一个点,比如我选择屏幕中心点,作为你的基准点,在你拖动的时候,根据手指拖动的距离去改变这个点坐标,传入绘制操作里是,画布就动起来了。

 class DrawThread extends Thread {
        @Override
        public void run() {
            while (flag) {
                long start = System.currentTimeMillis();
                drawItems();
                long end = System.currentTimeMillis();
                try {
                    if (end - start < 50) {
                        Thread.sleep(50 - (end - start));
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void drawItems() {
        try {
            canvas = mHolder.lockCanvas();
            if (canvas != null) {
                canvas.drawColor(bacColor);
                canvas.save();
                canvas.scale(rate, rate, cX, cY);
                if (null != lines && lines.size() != 0) {
                    for (int j = 0; j < lines.size(); j++) {
                        for (int k = 0; k < lines.get(j).getTargetElements().size(); k++) {
                            caculate(centerX + lines.get(j).getResourceX(), centerY + lines.get(j).getResourceY(), lines.get(j).getResourceR(), centerX + lines.get(j).getTargetElements().get(k).getTargetX(), centerY + lines.get(j).getTargetElements().get(k).getTargetY(),
                                    lines.get(j).getTargetElements().get(k).getTargetR() + 3, lines.get(j).getTargetElements().get(k).getText(), lines.get(j).getTargetElements().get(k).getTextColor(), lines.get(j).getTargetElements().get(k).getLineColor(), lines.get(j).getTargetElements().get(k).getTextSize());
                        }
                    }
                }

                if (null != circles && circles.size() > 0) {
                    for (int i = 0; i < circles.size(); i++) {
           
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值