Android课程思维导图,Android实现思维导图

最近,小弟在实现一个思维导图的开源控件。下面我简单介绍一下如下打造一个类似思维导图软件的ViewGroup。

5346384d71c4

基本结构.png

建立模型

主要模型结构相对简单:TreeModel,NoteModel,NoteView,TreeView。

核心实现分布如下:

TreeModel:树形结构的存储,树形结构的遍历,添加、删除节点;

NoteModel:节点关联的指向,和Parent的指向;

TreeView :绘制树形结构,对树形结构位置的纠正,实现View层的添加,删除,note关联绘制;

NoteView:显示text;

编写位置计算核心代码

在核心代码中,我想和大家分享的是TreeView如何对多种Style(树形形状)进行适配的问题。因为我们的树形结构的表达多种的,有的是一个半树形图,有点是圆形展开的等。对于这个问题,作为程序员如何进行解耦能,采用Interface进行解构适配,统一行为。所以在这里我写了一个TreeLayoutManager进行管理树形的位置表达。这里我实现了一个RightTreeLayoutManager。代码概况如下:

接口

public interface TreeLayoutManager {

/**

* 进行树形结构的位置计算

*/

void onTreeLayout(TreeView treeView);

/**

* 位置分布好后的回调,用于确认ViewGroup的大小

*/

ViewBox onTreeLayoutCallBack();

/**

* 修正位置

*

* @param treeView

* @param next

*/

void correctLayout(TreeView treeView, NodeView next);

}

实现

public class RightTreeLayoutManager implements TreeLayoutManager{

final int msg_standard_layout = 1;

final int msg_correct_layout = 2;

final int msg_box_call_back = 3;

private ViewBox mViewBox;

private int mDy;

private int mDx;

private int mHeight;

public RightTreeLayoutManager(int dx, int dy, int height) {

mViewBox = new ViewBox();

this.mDx = dx;

this.mDy = dy;

this.mHeight = height;

}

@Override

public void onTreeLayout(final TreeView treeView) {

final TreeModel mTreeModel = treeView.getTreeModel();

if (mTreeModel != null) {

View rootView = treeView.findNodeViewFromNodeModel(mTreeModel.getRootNode());

if (rootView != null) {

rootTreeViewLayout((NodeView) rootView);

}

mTreeModel.addForTreeItem(new ForTreeItem>() {

@Override

public void next(int msg, NodeModel next) {

doNext(msg, next, treeView);

}

});

//基本布局

mTreeModel.ergodicTreeInWith(msg_standard_layout);

//纠正

mTreeModel.ergodicTreeInWith(msg_correct_layout);

mViewBox.clear();

mTreeModel.ergodicTreeInDeep(msg_box_call_back);

}

}

@Override

public ViewBox onTreeLayoutCallBack() {

if (mViewBox != null) {

return mViewBox;

} else {

return null;

}

}

/**

* 布局纠正

*

* @param treeView

* @param next

*/

public void correctLayout(TreeView treeView, NodeView next) {

//主要是纠正对于标准布局出现的错误,譬如,在图片纠正中的那种情况

//纠正需要对同层的Note进行拉伸

}

/**

* 标准分布

*

* @param treeView

* @param rootView

*/

private void standardLayout(TreeView treeView, NodeView rootView) {

//标准分布主要是在基于root节点进行排开

//对于奇数和偶数不同的情况进行排开

//中间向外计算位置

}

/**

* 移动

*

* @param rootView

* @param dy

*/

private void moveNodeLayout(TreeView superTreeView, NodeView rootView, int dy) {

//如果一个note节点进行了移动,那么它

//会影响到它的子节点的位置。

//所以要进行重新计算,把它的所有的Note位置进行位移

}

/**

* root节点的定位

*

* @param rootView

*/

private void rootTreeViewLayout(NodeView rootView) {

int lr = mDy;

int tr = mHeight / 2 - rootView.getMeasuredHeight() / 2;

int rr = lr + rootView.getMeasuredWidth();

int br = tr + rootView.getMeasuredHeight();

rootView.layout(lr, tr, rr, br);

}

}

View的连线

要实现对View和View的连线,只要在View的位置定了之后,就进行画线即可。用Sketch画个演示如下:

5346384d71c4

Paste_Image.png

其中线为一个贝塞尔曲线。代码如下:

@Override

protected void dispatchDraw(Canvas canvas) {

if (mTreeModel != null) {

drawTreeLine(canvas, mTreeModel.getRootNode());

}

super.dispatchDraw(canvas);

}

/**

* 绘制树形的连线

*

* @param canvas

* @param root

*/

private void drawTreeLine(Canvas canvas, NodeModel root) {

NodeView fatherView = (NodeView) findNodeViewFromNodeModel(root);

if (fatherView != null) {

LinkedList> childNodes = root.getChildNodes();

for (NodeModel node : childNodes) {

//连线

drawLineToView(canvas, fatherView, findNodeViewFromNodeModel(node));

//递归

drawTreeLine(canvas, node);

}

}

}

/**

* 绘制两个View直接的连线

*

* @param canvas

* @param from

* @param to

*/

private void drawLineToView(Canvas canvas, View from, View to) {

if (to.getVisibility() == GONE) {

return;

}

Paint paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

float width = 2f;

paint.setStrokeWidth(dp2px(mContext, width));

paint.setColor(mContext.getResources().getColor(R.color.chelsea_cucumber));

int top = from.getTop();

int formY = top + from.getMeasuredHeight() / 2;

int formX = from.getRight();

int top1 = to.getTop();

int toY = top1 + to.getMeasuredHeight() / 2;

int toX = to.getLeft();

Path path = new Path();

path.moveTo(formX, formY);

path.quadTo(toX - dp2px(mContext, 15), toY, toX, toY);

canvas.drawPath(path, paint);

}

位置的纠正流程

位置纠正的问题;在对于我之前的位置的算法探索流程如下图,关键是写好已知的代码,之后纠正。

5346384d71c4

纠正.png

5346384d71c4

标准位置错误.png

5346384d71c4

标准位置错误的处理.png

观察发现,所有的移动都是基于被操作的点开始的上下之分的上下移动。

最后

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值