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

基本结构.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画个演示如下:

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);

}

位置的纠正流程

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

纠正.png

标准位置错误.png

标准位置错误的处理.png

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

最后

Android实现思维导图功能,Android实现思维导图相关推荐

  1. android仿微信发布动态功能,Android GridView扩展仿微信微博发图动态添加删除图片功能.pdf...

    Android GridView扩扩展展仿仿微微信信微微博博发发图图动动态态添添加加删删除除图图片片功功能能 这篇文章主要为大家详细介绍了Android GridView扩展仿微信微博发图动态添加删除 ...

  2. android中最新webview的功能,Android WebView实现截长图功能

    本文实例为大家分享了Android实现截长图功能的具体代码,供大家参考,具体内容如下 先看看手机自带的长截屏功能:  机型: vivo x9 plus 大胆推测实现逻辑: 1:需要一个可以滚动的Vie ...

  3. android仿微信发布动态功能,Android仿微信朋友圈发布动态功能

    一.前言 应工作上的要求,需要有一个类似于微信朋友圈发动态上传图片的功能,想起曾经已经做过了,但奈何不忍看自己以前写的代码的惨状,觉得重新封装一个使用方便,易于维护的类似功能的类,自己之后用起来也顺手 ...

  4. 京东商品长图功能来啦 不用改图一键生成长图

    产品是吸引顾客购买的关键,想要提升店铺转化率产品主图优化必不可少?首先基础优化是在设计主图的时候就要注意产品突出,使用场景来设计,根据产品的特点突出卖点,文案搭配要起到辅助的效果等等. 关于主图设计和 ...

  5. Python 技术篇-20行代码实现微信机器人斗图功能实例演示!斗图啦官网API调用方法

    话不多说,看效果图: 先说下原理: 微信接收到你说的话,发给机器人来回复,用回复的话传参给斗图网,然后获得斗图网返回的图片,保存后把图片再发给跟你斗图的人. 斗图啦官网API调用文档 斗图啦官网 菜单 ...

  6. android代码实现手机加速功能,Android自定义View实现内存清理加速球效果

    Android自定义View实现内存清理加速球效果 发布时间:2020-09-21 22:21:57 来源:脚本之家 阅读:105 作者:程序员的自我反思 前言 用过猎豹清理大师或者相类似的安全软件, ...

  7. Android实现拍照并存储功能,Android实现拍照及图片显示效果

    本文实例为大家分享了Android拍照及图片显示的具体代码,供大家参考,具体内容如下 1.功能声明 当应用需要使用相机.NFC等外设时,需要在AndroidManifest.xml中进行声明. 这样, ...

  8. Android已读未读功能,Android实现小圆点显示未读功能

    ####前言 以前我们实现这个功能都是用 BadgeView.java,大体就是将这个java类复制到自己的项目中,然后在项目中使用,今天讲的也是一款BadgeView,我将其封装称工具类Badget ...

  9. android有什么作用,Android 7.0有什么功能 Android N完整功能参数介绍

    类型:系统工具大小:1000M语言:中文 评分:10.0 标签: 立即下载 Android 7.0是安卓最近正在更新的一个版本,而其中也是有着很多的特性,在Android N的逐渐的曝光中,我们也是可 ...

  10. android 微信朋友圈 全功能,Android仿微信朋友圈文字展开全文功能 Android自定义TextView仿微信朋友圈文字展开全文功能...

    Android自定义TextView仿微信朋友圈文字信息,展开全文功能 代码及注释如下: 首先写一个xml文件 showmore.xml: android:orientation="vert ...

最新文章

  1. 使用按钮控制HTML5背景音乐开关
  2. 10篇Nature专题报导人类微生物组计划2(iHMP)成果及展望
  3. 如何在Eclipse中查看JDK以及JAVA框架的源码(转载)
  4. 警惕ASP网站Global.asa导致网站被挂马或转向
  5. linux 下串口编程VTIME和VMIN的设置
  6. java 写一个计算器_java编写一个计算器类
  7. 汉字转拼音,一二级词库,不支持多音字
  8. Linux配置http代理
  9. windows连接mysql程序_windows 连接mysql
  10. JavaMaven【二、目录结构HelloMaven】
  11. opencv4.3.0+Visual Studio 2019环境配置
  12. uvalive 3126 Taxi Cab Scheme
  13. android 步骤view,笔记20170530--自定义一个显示步骤的View(android)
  14. python语言属于哪一种语言阅读答案_python是一种()-智慧树Python语言应用章节答案...
  15. linux qt qpa linuxfb,Qt 5.4带有Tslib的Linux触摸屏输入在Raspberry Pi上无法使用LinuxFB QPA平台插件...
  16. WeChat-JSAPI支付
  17. 在Windows中如何通过命令行创建快捷方式
  18. oracle同义词6,oracle 同义词,oracle同义词是什么意思?
  19. 文秘计算机考核,行政文秘绩效考核
  20. python迅雷下载任务出错_迅雷下载任务出错的原因和解决方法 来研究下吧

热门文章

  1. CentOS之命令方式安装向日葵与内网穿透
  2. 韩立刚计算机网络——第七章:Internet 上面的音频和视频
  3. 2022电工(初级)考试模拟100题模拟考试平台操作
  4. Android NDK开发(一)环境搭建及运行示例
  5. Ubuntu搭建Android NDK开发环境并编译Demo
  6. 开发板串口复用的简单实现(一个串口连接二个串口模块)
  7. hpm1005能扫描不能打印_惠普M1005怎么只能打印复印不能扫描了?
  8. csv excel 对比
  9. 计算机无本地安全策略,如何打开本地安全策略、如何解决“未授予用户在此计算机上的请求登录类型”...
  10. digester_Apache Digester示例–轻松配置