Android 简易思维导图控件 ThinkMap
- 授权协议: GPL
- 开发语言: Java
- 操作系统: Android
- 软件首页: https://github.com/owant/ThinkMap
- 软件文档: https://github.com/owant/ThinkMap/blob/master/README.md
- 官方下载: https://github.com/owant/ThinkMap.git
软件介绍
实现Android端的简易思维导图。可以保存数据。编辑树形图。
建立模型
主要模型结构相对简单: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<String> mTreeModel = treeView.getTreeModel();
if (mTreeModel != null) {
View rootView = treeView.findNodeViewFromNodeModel(mTreeModel.getRootNode());
if (rootView != null) {
rootTreeViewLayout((NodeView) rootView);
}
mTreeModel.addForTreeItem(new ForTreeItem<NodeModel<String>>() {
@Override
public void next(int msg, NodeModel<String> 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画个演示如下:
其中线为一个贝塞尔曲线。代码如下:
@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<String> root) {
NodeView fatherView = (NodeView) findNodeViewFromNodeModel(root);
if (fatherView != null) {
LinkedList<NodeModel<String>> childNodes = root.getChildNodes();
for (NodeModel<String> 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);
}位置的纠正流程
位置纠正的问题;在对于我之前的位置的算法探索流程如下图,关键是写好已知的代码,之后纠正。
Practical Algorithms for Programmers
Andrew Binstock、John Rex / Addison-Wesley Professional / 1995-06-29 / USD 39.99
Most algorithm books today are either academic textbooks or rehashes of the same tired set of algorithms. Practical Algorithms for Programmers is the first book to give complete code implementations o......一起来看看 《Practical Algorithms for Programmers》 这本书的介绍吧!
