先看一下效果图:

这是通过贝瑟尔曲线绘制的一个生长的树的形态,这个是通过网易的公开课学到的东西 不是我搞的,看着比较有意思 发出来分享一下 好东西怎么能私藏呢四不四嫩 、文中会主要介绍代码,贝瑟尔曲线的内容大家可以去搜索其他文章了,流式布局的我就只提供源代码了,见谅 网上太多了呀,你要是想听我讲私信我哈,给你讲个三天三夜,这里就不赘述了 小板凳坐好了,上代码:
首先创建TreeView 类:
public class TreeView extends View {
// 存储
LinkedList<Branch> growingBranches;
private Paint paint;
private Canvas treeCanvas; // 缓存之前绘制的图片
private Bitmap bitmap = null;
public TreeView(Context context) {
this(context, null);
}
public TreeView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TreeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// init
paint = new Paint();
paint.setStrokeWidth(5);
growingBranches = new LinkedList<>();
// 树枝数据
growingBranches.add(getBranches());
}
private Branch getBranches() {
// id,parentID,bezier control point(3 points,int 6 columns),max radius ,length 里面的数据通过ps工具绘制一张树形图,然后获取各点坐标
int[][] data = new int[][]{
{0, -1, 217, 490, 252, 60, 182, 10, 30, 100},
{1, 0, 222, 310, 137, 227, 22, 210, 13, 100},
{2, 1, 132, 245, 116, 240, 76, 205, 2, 40},
{3, 0, 232, 255, 282, 166, 362, 155, 12, 100},
{4, 3, 260, 210, 330, 219, 343, 236, 3, 80},
{5, 0, 217, 91, 219, 58, 216, 27, 3, 40},
{6, 0, 228, 207, 95, 57, 10, 54, 9, 80},
{7, 6, 109, 96, 65, 63, 53, 15, 2, 40},
{8, 6, 180, 155, 117, 125, 77, 140, 4, 60},
{9, 0, 228, 167, 290, 62, 360, 31, 6, 100},
{10, 9, 272, 103, 328, 87, 330, 81, 2, 80}
};
int n = data.length;
// 循环数组
Branch[] branches = new Branch[n];
for (int i = 0; i < n; i++) {
branches[i] = new Branch(data[i]);
// 分组
int parentID = data[i][1];
if (parentID != -1) {
branches[parentID].addChild(branches[i]);
}
}
return branches[0];
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}
if (treeCanvas == null) {
treeCanvas = new Canvas(bitmap);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBranches();
canvas.drawBitmap(bitmap, 0, 0, paint);
}
private void drawBranches() {
if (!growingBranches.isEmpty()) {
LinkedList<Branch> tempBranches = null;
Iterator<Branch> iterator = growingBranches.iterator();
while (iterator.hasNext()) {
Branch branch = iterator.next();
// 生长
treeCanvas.save();
treeCanvas.translate(getWidth() / 2 - 217, getHeight() - 490);
if (!branch.grow(treeCanvas, paint, 1)) {
iterator.remove();
// 判断是否有分支
if (branch.childList != null) {
// 有分支
if (tempBranches == null) {
tempBranches = branch.childList;
} else {
tempBranches.addAll(branch.childList);
}
}
}
treeCanvas.restore();
}
if (tempBranches != null) {
growingBranches.addAll(tempBranches);
}
if (!growingBranches.isEmpty()) {
// 继续绘制
invalidate();
}
}
}
}
要是将树进行分解的话,这就是一个个的枝杈组成的一棵树,那么少了枝杈的类怎么行呢 创建branch类
public class Branch {
// 形状 (三个控制点)
private PointF[] cp = new PointF[3];
// 粗细
private float radius;
// 长度
private int maxLength;
private int currentLength;
private float part; // 一根树枝每一次绘制的长度
// 颜色
public static int branchColor = Color.CYAN;
// 分枝
LinkedList<Branch> childList;
// 绘制方法
private float growX, growY;
public Branch(int data[]) {
cp[0] = new PointF(data[2], data[3]);
cp[1] = new PointF(data[4], data[5]);
cp[2] = new PointF(data[6], data[7]);
radius = data[8];
maxLength = data[9];
part = 1f / maxLength;
}
/**
* 添加树枝枝杈
* @param branch
*/
public void addChild(Branch branch) {
if (childList == null) {
childList = new LinkedList<>();
}
childList.add(branch);
}
/**
* 生长方法
* @param canvas
* @param paint
* @param scalFactor 缩放比例
* @return
*/
public boolean grow(Canvas canvas, Paint paint, int scalFactor) {
if (currentLength < maxLength) {
// 计算当前绘制点的位置
bezier(part * currentLength);
// 绘制
draw(canvas, paint, scalFactor);
currentLength++;
radius *= 0.97f;
return true;
} else {
return false;
}
}
/**
* 贝瑟尔曲线公式
* @param t
*/
private void bezier(float t) {
float c0 = (1 - t) * (1 - t);
float c1 = 2 * t * (1 - t);
float c2 = t * t;
growX = c0 * cp[0].x + c1 * cp[1].x + c2 * cp[2].x;
growY = c0 * cp[0].y + c1 * cp[1].y + c2 * cp[2].y;
}
private void draw(Canvas canvas, Paint paint, int scalFactor) {
paint.setColor(branchColor);
canvas.save();
canvas.scale(scalFactor, scalFactor);
canvas.drawCircle(growX, growY, radius, paint);
canvas.restore(); // 不会影响后面的内容
}
就是这么两个类,看着比较简单是吧,哈哈,管它呢 有意思就完事了!附上源码链接 溜了 溜了 |