我正在为安卓开发思维导图工具。我正在为我的思维导图http://www.examtime.com/files/2013/08/How-to-create-an-online-mind-map.jpg创建这种类型的布局。有什么方法可以创建这些类型的线(如图像中创建的)以在运行时连接对象。请帮忙
1 回答
您应该研究三次贝塞尔曲线(样条曲线)。没有简单的方法可以简单地使用 Canvas 来做到这一点。这是一个概述:
贝塞尔曲线使用 2 个点(P0 - 起点和 P1 - 终点)和 2 个向量(V0 - 曲线离开 P0 的方向,V1 - 曲线进入 P1 的方向)。对于我们的目的,P0、P1、V0、V1 都应该是类型PointF
。
我们将使用 t 来表示路径上的位置。当 t = 0 时,位置在 P0,当 t = 1 时,位置在 P1。任何介于 0 和 1 之间的 t 值都将沿着路径。0 <= t <= 1。
现在,作为一个例子,让我们看看连接“Nobody's perfect”节点和“Tidy up later”节点的曲线。
在这种情况下,P0 将是“Nobody's perfect”的右中边,P1 将是“Tidy up later”的底部中边。
我们将使两个向量都垂直于它们离开/进入的节点,因此 V0 的值将是 {P1.x - P0.x, 0}。该向量将指向右侧,并且具有与两个节点之间的距离相等的强度。以类似的方式,我们将构建指向节点的 V1 向量:{0, P0.y - P1.y}
现在您已经有了向量和点,您将要开始绘制曲线。为此,您将使用一些可被 1 整除的小步进值迭代 t,例如 0.1、0.025、0.001 等。让我们将此值称为“步长” 每次迭代都会在曲线上生成一个点,并且您'会想要在每个点之间连接一条线。
这是此部分的代码示例:
PointF start, end;
for (float t = 0; t < 1; t += step)
{
start = getBezierPosition(t);
end = getBezierPosition(t + step)
canvas.drawLine(start.x, start.y, end.x, end.y, paint);
}
现在,困难的部分 - 计算位置 t 处的贝塞尔曲线的位置:
private PointF getBezierPosition(float t)
{
PointF result = new PointF();
float oneMinusT, x, y;
oneMinusT = 1 - t;
x = oneMinusT * oneMinusT * oneMinusT * P0.x +
3 * oneMinusT * oneMinusT * t * V0.x +
3 * oneMinusT * t * t * V1.x +
t * t * t * P1.x;
y = oneMinusT * oneMinusT * oneMinusT * P0.y +
3 * oneMinusT * oneMinusT * t * V0.y +
3 * oneMinusT * t * t * V1.y +
t * t * t * P1.y;
result.set(x, y);
return result;
}
这是三次贝塞尔曲线的公式。您可以在此处了解更多信息。
我将让您实现确定 P0 和 P1 的位置以及 V0 和 V1 的方向的逻辑(请记住,它们应该始终垂直于它们离开/进入的节点以获得最佳结果)。您需要使用逻辑来确定 P 位于节点的哪一侧,并且它很可能与您将节点定位在第一个位置所应用的逻辑相关联。
此外,为了获得最佳效果,请尝试使用您正在绘制的油漆的笔画宽度。例如,当 t = 0 时,使用大小为 5 的笔画宽度,当 t = 1 时,使用大小为 3 的笔画。确保在它们之间平滑迭代(因此,如果 t = 0.5,笔画宽度将为 4) .
我承认,这东西在数学上有点重,可能不是初学者的舒适区,但如果你想实现你在这张照片中显示的动态曲线,恐怕你会去弄脏你的手。
祝你好运!让我知道结果如何:)