父类中定义好所有需要的东西,其实就是从BaseDraw中复制出来的属性,对与树叶来说,他们不具备添加另一个树叶或树枝的能力,所以不需要重写add、remove、getChild方法,树枝拥有这些能力,重写这些方法就能实现添加的能力
树叶,以圆的图元为例,其他树叶都是差不多的
public class CircularData extends BaseData { public CircularData(TypeEnum typeEnum, int wight, int paintAlpha, int offset, int count, float[] floats, RectF rectF, Paint.Style style) { super(typeEnum, wight, paintAlpha, offset, count, floats, rectF, style); } @Override public void move(float moveX, float moveY) { float[] floats = {getFloats()[0] + moveX, getFloats()[1] + moveY, getFloats()[2]}; setFloats(floats); } @Override public void draw(Canvas canvas) { CircularDraw circularDraw = new CircularDraw(this); circularDraw.drawPicture(canvas); } @Override public DataType[] pointIsInside(float moveX, float moveY) { float x = getFloats()[0]; float y = getFloats()[1]; float r = getFloats()[2]; if ((x + r > moveX && moveX > x - r) && (y + r > moveY && moveY > y - r)) { return new DataType[]{DataType.In, DataType.Leaf}; } return new DataType[]{DataType.Out, DataType.Leaf}; } }因为这个类,知道自己就是圆,所以我可以直接new 一个圆的绘制类,然后把View传过来的Canvas,和自己传给绘制类,自己是一个图元,Canvas是唯一的,Paint早就实例化了的各种属性也设置好了,就可以直接再Canvas上画出圆。move方法,是获取屏幕的点击坐标,传入x,y值,更改与画圆有关的属性,pointIsInside方法,是判断,当屏幕被点击的点,是不是在我的绘制区域内
DataType是一个枚举
public enum DataType { In , Out , Leaf ,Root }返回一个枚举数组就知道这个点在不在之中,这个图形时枝还是叶。
树枝
public class CompositeData extends BaseData { public CompositeData(TypeEnum typeEnum, int wight, int paintAlpha, int offset, int count, float[] floats, RectF rectF, Paint.Style style) { super(typeEnum, wight, paintAlpha, offset, count, floats, rectF, style); } private List childComponents = new ArrayList(); @Override public void move(float moveX, float moveY) { if (childComponents != null) { for (BaseData baseData : childComponents) { baseData.move(moveX, moveY); } } } @Override public DataType[] pointIsInside(float moveX, float moveY) { if (childComponents != null) { for (BaseData baseData : childComponents) { DataType dataType[] = baseData.pointIsInside(moveX, moveY); if (dataType[0] == DataType.In) { return new DataType[]{DataType.In, DataType.Root}; } } } return new DataType[]{DataType.Out, DataType.Root}; } @Override public void addChild(BaseData baseData) { childComponents.add(baseData); } @Override public void removeChild(int index) { childComponents.remove(index); } @Override public List getChild() { return childComponents; } @Override public void draw(Canvas canvas) { if (childComponents != null) { for (BaseData baseData : childComponents) { baseData.draw(canvas); } } CompositeDraw compositeDraw = new CompositeDraw(this); compositeDraw.drawPicture(canvas); } }树枝中有一个List,是用来储存添加的叶、枝的,当树枝要移动是树叶也要移动,所以,移动树枝,就是树枝遍历自己list里的图元对象,然后调用图元的move方法。draw也是一样的,而当判断点击的点在不在这个树枝的区域内时,只要这个点在树枝任意一个树叶的范围内,我们所返回的枚举数组就是{在,树枝},这里我只有移动,放大、缩小,后面一步步完善再贴上来。
现在为了绘图我们需要一个View和Canvas
DrawView
public class DrawView extends View { Context context; BaseData baseData; public DrawView(Context context) { super(context); this.context = context; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (baseData != null) { baseData.draw(canvas); } } public BaseData getBaseDraw() { return baseData; } public void upData(BaseData baseData) { this.baseData = baseData; postInvalidate(); } public void move(float moveX , float moveY){ if (baseData != null){ baseData.move(moveX ,moveY); postInvalidate(); } } }baseData是包含了所有枝、叶的实例,在onDraw中,baseData调用draw时,遇到叶会直接画出来,遇到枝,枝会把自己所包含的枝、叶一个接一个的遍历然后画出来。