Android 自定义View之生长树、流式布局

先看一下效果图:

                   

这是通过贝瑟尔曲线绘制的一个生长的树的形态,这个是通过网易的公开课学到的东西 不是我搞的,看着比较有意思 发出来分享一下 好东西怎么能私藏呢四不四嫩 、文中会主要介绍代码,贝瑟尔曲线的内容大家可以去搜索其他文章了,流式布局的我就只提供源代码了,见谅 网上太多了呀,你要是想听我讲私信我哈,给你讲个三天三夜,这里就不赘述了 小板凳坐好了,上代码:

首先创建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(); // 不会影响后面的内容
    }

就是这么两个类,看着比较简单是吧,哈哈,管它呢 有意思就完事了!附上源码链接 溜了 溜了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值