用SurfaceView实现级联分层图(粗略篇)

先看效果图

实际运行很流畅,运行内存1M左右

这里写图片描述

最近脑抽,想实现一个亲戚关系图谱的应用,但始终没有找到合适的开源控件,于是就看到一篇《利用递归算法和堆栈实现android思维导图大纲图的动态绘制》实现类似效果的文章,并附上效果图
一张

于是就想,想这种的自定义控件貌似在线上很少可看到(我自己是没有看到过)

那么在Android端实现起来,需要怎么写

经过一番思考
1.继承ViewGroup来写?然后线怎么绘制。。
2.线的绘制需要Canvas,用到画布画笔
3.有了画布画笔,线的绘制需要开始xy,结束xy
4.绘制是动态的,ViewGroup的话需要用到异步来绘制
5.Canvas异步绘制?那绘制时的数据怎么保证同步
6.于是有了这些条件:异步绘制,数据同步,用到画布,那不就是SurfaceView的宿命吗

不了解SurfaceView的同学请补一下SurfaceView的基础用法

有了这些基础和条件之后,就开始写代码了

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    public LoopThread loopThread;

    public static final int START_X = 150;
    public static final int START_Y = 500;


    public MySurfaceView(Context context) {
        super(context);

        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        loopThread = new LoopThread(holder, context);
    }

    public MySurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        loopThread.isRunning = true;
        loopThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        loopThread.isRunning = false;
        try {
            loopThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public class LoopThread extends Thread {

        final SurfaceHolder holder;
        Context context;
        Paint paint;

        //是否停止绘制
        boolean isRunning = false;

        float radius = 10f,
                radius2 = 10f,
                length = 10f,
                height = 10f,
                secondLength = 10f;

        float maxRadius = 120,
                maxRadius2 = 90,
                maxLength = 150,
                maxHeight = maxRadius * 2;

        LoopThread(SurfaceHolder holder, Context context) {
            this.holder = holder;
            this.context = context;

            paint = new Paint();
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.FILL);
        }

        @Override
        public void run() {
            Canvas c = null;

            while (isRunning) {
                try {
                    synchronized (holder) {
                        c = holder.lockCanvas(null);
                        draw(c);
//                        Thread.sleep(100);
                    }
                } finally {
                    holder.unlockCanvasAndPost(c);
                }
            }
        }

        private void draw(Canvas canvas) {
            //clear screen
            canvas.drawColor(Color.WHITE);

            if (radius <= maxRadius) {//画第一个圆
                canvas.translate(START_X, START_Y);
                canvas.drawCircle(0, 0, radius += 10, paint);

                Paint paint1 = new Paint();
                paint1.setColor(Color.RED);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setTypeface(Typeface.DEFAULT_BOLD);
                paint1.setTextSize(radius > maxRadius / 2 ? maxRadius / 2 : radius);
                canvas.drawText("hello", radius > maxRadius / 2 ? -maxRadius / 2 : -radius, radius > maxRadius / 2 ? maxRadius / 5 : radius, paint1);
            } else if (radius > maxRadius && length < maxLength) {//画横
                canvas.translate(START_X, START_Y);
                canvas.drawCircle(0, 0, maxRadius, paint);

                Paint paint = new Paint();
                paint.setColor(Color.RED);
                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(maxRadius / 2);
                canvas.drawText("hello", -maxRadius / 2, maxRadius / 5, paint);

                canvas.translate(radius, 0);

                Paint paint1 = new Paint();
                paint1.setColor(Color.BLUE);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setStrokeWidth(5f);

                canvas.drawLine(0, 0, length += 30, 0, paint1);
            } else if (height <= maxHeight) {//画竖线
                canvas.translate(START_X, START_Y);
                canvas.drawCircle(0, 0, radius, paint);

                Paint paint = new Paint();
                paint.setColor(Color.RED);
                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(maxRadius / 2);
                canvas.drawText("hello", -maxRadius / 2, maxRadius / 5, paint);

                canvas.translate(radius, 0);

                Paint paint1 = new Paint();
                paint1.setColor(Color.BLUE);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setStrokeWidth(5f);

                canvas.drawLine(0, 0, length, 0, paint1);

                canvas.translate(length, 0);
                canvas.drawLine(0, -height / 2, 0, height += 50, paint1);
            } else if (secondLength <= maxLength) {//画3横
                canvas.translate(START_X, START_Y);
                canvas.drawCircle(0, 0, radius, paint);

                Paint paint = new Paint();
                paint.setColor(Color.RED);
                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(maxRadius / 2);
                canvas.drawText("hello", -maxRadius / 2, maxRadius / 5, paint);

                canvas.translate(radius, 0);

                Paint paint1 = new Paint();
                paint1.setColor(Color.BLUE);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setStrokeWidth(5f);

                canvas.drawLine(0, 0, length, 0, paint1);

                canvas.translate(length, 0);
                canvas.drawLine(0, -(START_Y + height) / 2, 0, (START_Y + height) / 2, paint1);

                canvas.translate(0, -(START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength += 30, 0, paint1);

                canvas.translate(0, (START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength, 0, paint1);

                canvas.translate(0, (START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength, 0, paint1);
            } else {//画3圆
                canvas.translate(START_X, START_Y);
                canvas.drawCircle(0, 0, radius, paint);

                Paint paint = new Paint();
                paint.setColor(Color.RED);
                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(maxRadius / 2);
                canvas.drawText("hello", -maxRadius / 2, maxRadius / 5, paint);

                canvas.translate(radius, 0);

                Paint paint1 = new Paint();
                paint1.setColor(Color.BLUE);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setStrokeWidth(5f);

                canvas.drawLine(0, 0, length, 0, paint1);

                canvas.translate(length, 0);
                canvas.drawLine(0, -(START_Y + height) / 2, 0, (START_Y + height) / 2, paint1);

                canvas.translate(0, -(START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength, 0, paint1);

                canvas.translate(0, (START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength, 0, paint1);

                canvas.translate(0, (START_Y + height) / 2);
                canvas.drawLine(0, 0, secondLength, 0, paint1);

                //第二层第1个圆
                canvas.translate(radius2 + secondLength, -(START_Y + height));
                canvas.drawCircle(0, 0, radius2 += 30, this.paint);

                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(radius2 > maxRadius2 / 2 ? maxRadius2 / 2 : radius2);
                canvas.drawText("haha", radius2 > maxRadius2 / 2 ? -maxRadius2 / 2 : -radius2, maxRadius2/5, paint);

                //第二层第2个圆
                canvas.translate(0, (START_Y + height) / 2);
                canvas.drawCircle(0, 0, radius2, this.paint);

                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(radius2 > maxRadius2 / 2 ? maxRadius2 / 2 : radius2);
                canvas.drawText("haha", radius2 > maxRadius2 / 2 ? -maxRadius2 / 2 : -radius2, maxRadius2/5, paint);

                //第二层第3个圆
                canvas.translate(0, (START_Y + height) / 2);
                RectF rectF = new RectF();
                rectF.left = -maxRadius2;
                rectF.right = maxRadius2;
                rectF.top = -maxRadius2;
                rectF.bottom = maxRadius2;
                canvas.drawRoundRect(rectF, 10, 10, this.paint);

                paint.setStyle(Paint.Style.FILL);
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setTextSize(radius2 > maxRadius2 / 2 ? maxRadius2 / 2 : radius2);
                canvas.drawText("haha", radius2 > maxRadius2 / 2 ? -maxRadius2 / 2 : -radius2, maxRadius2/5, paint);

                if (radius2 > 90) {
                    isRunning = false;
                }
            }
        }
    }
}

代码都是很基本的绘制,没有什么特别的
目前该控件的缺点很多很多,以后有可能拓展的方向:可拖拽缩放大小 、动态绘制分级并画线、添加控件的点击事件

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值