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

来源:互联网 发布:淘宝装修教程 编辑:程序博客网 时间:2024/06/06 03:08

先看效果图

实际运行很流畅,运行内存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 0