先看效果图
实际运行很流畅,运行内存1M左右
![这里写图片描述](https://img-blog.csdn.net/20161011180644990)
最近脑抽,想实现一个亲戚关系图谱的应用,但始终没有找到合适的开源控件,于是就看到一篇《利用递归算法和堆栈实现android思维导图大纲图的动态绘制》实现类似效果的文章,并附上效果图
![一张](https://img-blog.csdn.net/20161011181143903)
于是就想,想这种的自定义控件貌似在线上很少可看到(我自己是没有看到过)
那么在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
}
}
}
}
}
代码都是很基本的绘制,没有什么特别的
目前该控件的缺点很多很多,以后有可能拓展的方向:可拖拽缩放大小 、动态绘制分级并画线、添加控件的点击事件
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)