Android树形控件绘制方法

前言

作为一个开发者,日常会接触到很多优秀的软件,其实,或多或少会有这样的想法,我能不能开发一个自己软件,甚至办公软件都希望是Markdown的文本,为何用office?我常常想自己做一个IDE什么的。但是,很多只是想了一下就过了,一直没有实现.
我接触思维导图软件已经很久的了,开始是使用微软的思维导图软件,接着XMind,后来使用了MindMaple Lite。感觉很好用的。也想过如何去实现一个思维导图的软件,加之我特别注意软件的快捷键,我选取软件常常是,看快捷如何,快捷键差的就不要了。基于自己的实践使用思维导图。前一个月我就在github上实现了一个树形图的Android控件,这个其实是我想实现思维导图的开始。实现后,才发现并没有多大的障碍。下面我就说说我如何打造一个树形控件的。先上效果:

效果1

效果2

实现

一步一步可夺城。将自己要实现的东西肢解,那些实现得了的?那些未知的?

思路步骤概要

整个结构分为:树形,节点; 对于Android的结构有:模型(树形,节点),View;

实现树形的节点node 的Model; 实现树形Model; 实现View的绘制:1.添加View;2.确定Nodes的位置;3.连线Node;

详细步骤

看到思路步骤概要后,相信我们的思路已经很清晰了。感觉是不是很simple,是的,实现也如此。到这里了,我就开始编码。但是为了教会大家,我提几个疑问给大家:

树的遍历如何实现?(可以google,如果你学过数据结构当然simple了)
节点和节点这间使用什么关联?(next)
如何确定Node的位置?位置有什么规律?(??)
如何实现两个View之间的连线?(??)
……

其实问题还真的有一点。但是这些都不能妨碍我们的步伐,还是写好已知的代码吧 。

代码

1.树的节点。主要是一些需要的数据。父节点,值,子节点,是否对焦(对于将来用的),在树形的层……

package com.owant.drawtreeview.model; import java.util.LinkedList; /** * Created by owant on 16/12/2016. */ public class TreeNode<T> { /** * the parent node,if root node parent node=null; */ public TreeNode<T> parentNode; /** * the data value */ public T value; /** * have the child nodes */ public LinkedList<TreeNode<T>> childNodes; /** * focus tag for the tree add nodes */ public boolean focus; /** * index of the tree floor */ public int floor; public TreeNode(T value) { this.value = value; this.childNodes = new LinkedList<TreeNode<T>>(); // this.focus = false; // this.parentNode = null; } public TreeNode<T> getParentNode() { return parentNode; } public void setParentNode(TreeNode<T> parentNode) { this.parentNode = parentNode; } public T getValue() { return value; } public void setValue(T value) { this.value = value; } public LinkedList<TreeNode<T>> getChildNodes() { return childNodes; } public void setChildNodes(LinkedList<TreeNode<T>> childNodes) { this.childNodes = childNodes; } public boolean isFocus() { return focus; } public void setFocus(boolean focus) { this.focus = focus; } public int getFloor() { return floor; } public void setFloor(int floor) { this.floor = floor; } }

2.树形。根节点,添加节点,遍历,上一个节点,下一个节点,基于点拆分的上下节点集合。

package com.owant.drawtreeview.model; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.Stack; /** * Created by owant on 16/12/2016. */ public class Tree<T> { /** * the root for the tree */ public TreeNode<T> rootNode; public Tree(TreeNode<T> rootNode) { this.rootNode = rootNode; } /** * add the node in some father node * * @param start * @param nodes */ public void addNode(TreeNode<T> start, TreeNode<T>... nodes) { int index = 1; TreeNode<T> temp = start; if (temp.getParentNode() != null) { index = temp.getParentNode().floor; } for (TreeNode<T> t : nodes) { t.setParentNode(start); t.setFloor(index); start.getChildNodes().add(t); } } public boolean remvoeNode(TreeNode<T> starNode, TreeNode<T> deleteNote) { boolean rm = false; int size = starNode.getChildNodes().size(); if (size > 0) { rm = starNode.getChildNodes().remove(deleteNote); } return rm; } public TreeNode<T> getRootNode() { return rootNode; } public void setRootNode(TreeNode<T> rootNode) { this.rootNode = rootNode; } /** * 同一个父节点的上下 * * @param midPreNode * @return * @throws NotFindNodeException */ public TreeNode<T> getLowNode(TreeNode<T> midPreNode) { TreeNode<T> find = null; TreeNode<T> parentNode = midPreNode.getParentNode(); if (parentNode != null && parentNode.getChildNodes().size() >= 2) { Deque<TreeNode<T>> queue = new ArrayDeque<>(); TreeNode<T> rootNode = parentNode; queue.add(rootNode); boolean up = false; while (!queue.isEmpty()) { rootNode = (TreeNode<T>) queue.poll(); if (up) { if (rootNode.getFloor() == midPreNode.getFloor()) { find = rootNode; } break; } //到了该元素 if (rootNode == midPreNode) up = true; LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes(); if (childNodes.size() > 0) { for (TreeNode<T> item : childNodes) { queue.add(item); } } } } return find; } public TreeNode<T> getPreNode(TreeNode<T> midPreNode) { TreeNode<T> parentNode = midPreNode.getParentNode(); TreeNode<T> find = null; if (parentNode != null && parentNode.getChildNodes().size() > 0) { Deque<TreeNode<T>> queue = new ArrayDeque<>(); TreeNode<T> rootNode = parentNode; queue.add(rootNode); while (!queue.isEmpty()) { rootNode = (TreeNode<T>) queue.poll(); //到了该元素 if (rootNode == midPreNode) { //返回之前的值 break; } find = rootNode; LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes(); if (childNodes.size() > 0) { for (TreeNode<T> item : childNodes) { queue.add(item); } } } if (find != null && find.getFloor() != midPreNode.getFloor()) { find = null; } } return find; } public ArrayList<TreeNode<T>> getAllLowNodes(TreeNode<T> addNode) { ArrayList<TreeNode<T>> array = new ArrayList<>(); TreeNode<T> parentNode = addNode.getParentNode(); while (parentNode != null) { TreeNode<T> lowNode = getLowNode(parentNode); while (lowNode != null) { array.add(lowNode); lowNode = getLowNode(lowNode); } parentNode = parentNode.getParentNode(); } return array; } public ArrayList<TreeNode<T>> getAllPreNodes(TreeNode<T> addNode) { ArrayList<TreeNode<T>> array = new ArrayList<>(); TreeNode<T> parentNode = addNode.getParentNode(); while (parentNode != null) { TreeNode<T> lowNode = getPreNode(parentNode); while (lowNode != null) { array.add(lowNode); lowNode = getPreNode(lowNode); } parentNode = parentNode.getParentNode(); } return array; } public LinkedList<TreeNode<T>> getNodeChildNodes(TreeNode<T> node) { return node.getChildNodes(); } public void printTree() { Stack<TreeNode<T>> stack = new Stack<>(); TreeNode<T> rootNode = getRootNode(); stack.add(rootNode); while (!stack.isEmpty()) { TreeNode<T> pop = stack.pop(); System.out.println(pop.getValue().toString()); LinkedList<TreeNode<T>> childNodes = pop.getChildNodes(); for (TreeNode<T> item : childNodes) { stack.add(item); } } } public void printTree2() { Deque<TreeNode<T>> queue = new ArrayDeque<>(); TreeNode<T> rootNode = getRootNode(); queue.add(rootNode); while (!queue.isEmpty()) { rootNode = (TreeNode<T>) queue.poll(); System.out.println(rootNode.getValue().toString()); LinkedList<TreeNode<T>> childNodes = rootNode.getChildNodes(); if (childNodes.size() > 0) { for (TreeNode<T> item : childNodes) { queue.add(item); } } } } }

3.测试模型 当我们实现了模型后,要写一些列子来测试模型是否正确,进行打印,遍历等测试,这是很重要的。对于树形的node的上一个node和下一个node的理解等。

4.树形的View

package com.owant.drawtreeview.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import com.owant.drawtreeview.R; import com.owant.drawtreeview.model.Tree; import com.owant.drawtreeview.model.TreeNode; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; /** * Created by owant on 09/01/2017. */ public class SuperTreeView extends ViewGroup { /** * the default x,y mDx */ private int mDx; private int mDy; private int mWith; private int mHeight; private Context mContext; private Tree<String> mTree; private ArrayList<NodeView> mNodesViews; public SuperTreeView(Context context) { this(context, null, 0); } public SuperTreeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SuperTreeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; mNodesViews = new ArrayList<>(); mContext = context; mDx = dp2px(mContext, 26); mDy = dp2px(mContext, 22); } /** * 添加view到Group */ private void onAddNodeViews() { if (mTree != null) { TreeNode<String> rootNode = mTree.getRootNode(); Deque<TreeNode<String>> deque = new ArrayDeque<>(); deque.add(rootNode); while (!deque.isEmpty()) { TreeNode<String> poll = deque.poll(); NodeView nodeView = new NodeView(mContext); nodeView.setTreeNode(poll); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); nodeView.setLayoutParams(lp); this.addView(nodeView); mNodesViews.add(nodeView); LinkedList<TreeNode<String>> childNodes = poll.getChildNodes(); for (TreeNode<String> ch : childNodes) { deque.push(ch); } } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int size = getChildCount(); for (int i = 0; i < size; i++) { measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mHeight = getMeasuredHeight(); mWith = getMeasuredWidth(); if (mTree != null) { NodeView rootView = findTreeNodeView(mTree.getRootNode()); if (rootView != null) { //root的位置 rootTreeViewLayout(rootView); //标准位置 for (NodeView nv : mNodesViews) { standardTreeChildLayout(nv); } //基于父子的移动 for (NodeView nv : mNodesViews) { fatherChildCorrect(nv); } } } } 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); } @Override protected void dispatchDraw(Canvas canvas) { if (mTree != null) { drawTreeLine(canvas, mTree.getRootNode()); } super.dispatchDraw(canvas); } /** * 标准的位置分布 * * @param rootView */ private void standardTreeChildLayout(NodeView rootView) { TreeNode<String> treeNode = rootView.getTreeNode(); if (treeNode != null) { //所有的子节点 LinkedList<TreeNode<String>> childNodes = treeNode.getChildNodes(); int size = childNodes.size(); int mid = size / 2; int r = size % 2; //基线 // b // a------- // c // int left = rootView.getRight() + mDx; int top = rootView.getTop() + rootView.getMeasuredHeight() / 2; int right = 0; int bottom = 0; if (size == 0) { return; } else if (size == 1) { NodeView midChildNodeView = findTreeNodeView(childNodes.get(0)); top = top - midChildNodeView.getMeasuredHeight() / 2; right = left + midChildNodeView.getMeasuredWidth(); bottom = top + midChildNodeView.getMeasuredHeight(); midChildNodeView.layout(left, top, right, bottom); } else { int topLeft = left; int topTop = top; int topRight = 0; int topBottom = 0; int bottomLeft = left; int bottomTop = top; int bottomRight = 0; int bottomBottom = 0; if (r == 0) {//偶数 for (int i = mid - 1; i >= 0; i--) { NodeView topView = findTreeNodeView(childNodes.get(i)); NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1)); if (i == mid - 1) { topTop = topTop - mDy / 2 - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy / 2; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); } else { topTop = topTop - mDy - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); } topView.layout(topLeft, topTop, topRight, topBottom); bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); bottomTop = bottomView.getBottom(); } } else { NodeView midView = findTreeNodeView(childNodes.get(mid)); midView.layout(left, top - midView.getMeasuredHeight() / 2, left + midView.getMeasuredWidth(), top - midView.getMeasuredHeight() / 2 + midView.getMeasuredHeight()); topTop = midView.getTop(); bottomTop = midView.getBottom(); for (int i = mid - 1; i >= 0; i--) { NodeView topView = findTreeNodeView(childNodes.get(i)); NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1)); topTop = topTop - mDy - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); topView.layout(topLeft, topTop, topRight, topBottom); bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); bottomTop = bottomView.getBottom(); } } } } } /** * 移动 * * @param rootView * @param dy */ private void moveNodeLayout(NodeView rootView, int dy) { Deque<TreeNode<String>> queue = new ArrayDeque<>(); TreeNode<String> rootNode = rootView.getTreeNode(); queue.add(rootNode); while (!queue.isEmpty()) { rootNode = (TreeNode<String>) queue.poll(); rootView = findTreeNodeView(rootNode); int l = rootView.getLeft(); int t = rootView.getTop() + dy; rootView.layout(l, t, l + rootView.getMeasuredWidth(), t + rootView.getMeasuredHeight()); LinkedList<TreeNode<String>> childNodes = rootNode.getChildNodes(); for (TreeNode<String> item : childNodes) { queue.add(item); } } } private void fatherChildCorrect(NodeView nv) { int count = nv.getTreeNode().getChildNodes().size(); if (nv.getParent() != null && count >= 2) { TreeNode<String> tn = nv.getTreeNode().getChildNodes().get(0); TreeNode<String> bn = nv.getTreeNode().getChildNodes().get(count - 1); Log.i("see fc", nv.getTreeNode().getValue() + ":" + tn.getValue() + "," + bn.getValue()); int topDr = nv.getTop() - findTreeNodeView(tn).getBottom() + mDy; int bnDr = findTreeNodeView(bn).getTop() - nv.getBottom() + mDy; //上移动 ArrayList<TreeNode<String>> allLowNodes = mTree.getAllLowNodes(bn); ArrayList<TreeNode<String>> allPreNodes = mTree.getAllPreNodes(tn); for (TreeNode<String> low : allLowNodes) { NodeView view = findTreeNodeView(low); moveNodeLayout(view, bnDr); } for (TreeNode<String> pre : allPreNodes) { NodeView view = findTreeNodeView(pre); moveNodeLayout(view, -topDr); } } } /** * 绘制树形的连线 * * @param canvas * @param root */ private void drawTreeLine(Canvas canvas, TreeNode<String> root) { NodeView fatherView = findTreeNodeView(root); if (fatherView != null) { LinkedList<TreeNode<String>> childNodes = root.getChildNodes(); for (TreeNode<String> node : childNodes) { drawLineToView(canvas, fatherView, findTreeNodeView(node)); drawTreeLine(canvas, node); } } } /** * 绘制两个View直接的连线 * * @param canvas * @param from * @param to */ private void drawLineToView(Canvas canvas, View from, View to) { 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); } private NodeView findTreeNodeView(TreeNode<String> node) { NodeView v = null; for (NodeView view : mNodesViews) { if (view.getTreeNode() == node) { v = view; continue; } } return v; } public int dp2px(Context context, float dpVal) { int result = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources() .getDisplayMetrics()); return result; } public void setTree(Tree<String> tree) { this.mTree = tree; onAddNodeViews(); } public Tree<String> getTree() { return mTree; } }

粘贴代码后发现,没有什么好说了,对于读者来说,应该是一脸懵逼的。毕竟,那个位置是如何确定的呀,view和view的连线呀…… 对于整个View来说这是最难的,我也是探索了好久才得出结论的。首先,对于一个只有两层的树形来说,如图:

PQRS是基于F来计算的,之后分布。之后我就得到的方法如下:

/** * 标准的位置分布 * * @param rootView */ private void standardTreeChildLayout(NodeView rootView) { TreeNode<String> treeNode = rootView.getTreeNode(); if (treeNode != null) { //所有的子节点 LinkedList<TreeNode<String>> childNodes = treeNode.getChildNodes(); int size = childNodes.size(); int mid = size / 2; int r = size % 2; //基线 // b // a------- // c // int left = rootView.getRight() + mDx; int top = rootView.getTop() + rootView.getMeasuredHeight() / 2; int right = 0; int bottom = 0; if (size == 0) { return; } else if (size == 1) { NodeView midChildNodeView = findTreeNodeView(childNodes.get(0)); top = top - midChildNodeView.getMeasuredHeight() / 2; right = left + midChildNodeView.getMeasuredWidth(); bottom = top + midChildNodeView.getMeasuredHeight(); midChildNodeView.layout(left, top, right, bottom); } else { int topLeft = left; int topTop = top; int topRight = 0; int topBottom = 0; int bottomLeft = left; int bottomTop = top; int bottomRight = 0; int bottomBottom = 0; if (r == 0) {//偶数 for (int i = mid - 1; i >= 0; i--) { NodeView topView = findTreeNodeView(childNodes.get(i)); NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1)); if (i == mid - 1) { topTop = topTop - mDy / 2 - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy / 2; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); } else { topTop = topTop - mDy - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); } topView.layout(topLeft, topTop, topRight, topBottom); bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); bottomTop = bottomView.getBottom(); } } else { NodeView midView = findTreeNodeView(childNodes.get(mid)); midView.layout(left, top - midView.getMeasuredHeight() / 2, left + midView.getMeasuredWidth(), top - midView.getMeasuredHeight() / 2 + midView.getMeasuredHeight()); topTop = midView.getTop(); bottomTop = midView.getBottom(); for (int i = mid - 1; i >= 0; i--) { NodeView topView = findTreeNodeView(childNodes.get(i)); NodeView bottomView = findTreeNodeView(childNodes.get(size - i - 1)); topTop = topTop - mDy - topView.getMeasuredHeight(); topRight = topLeft + topView.getMeasuredWidth(); topBottom = topTop + topView.getMeasuredHeight(); bottomTop = bottomTop + mDy; bottomRight = bottomLeft + bottomView.getMeasuredWidth(); bottomBottom = bottomTop + bottomView.getMeasuredHeight(); topView.layout(topLeft, topTop, topRight, topBottom); bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); bottomTop = bottomView.getBottom(); } } } } }

之后等到的View情况如下:

说明我们还需要纠正。下面是纠正的探索,我精简一下结构如下情况:

发现:

B需要在E的上面;
D需要在I的下面;

就是EI要撑开ID的位置。之后我们可以先写这个算法,发现基本可以了。但是还是有问题,同层的还是会重合,只有我们又进行同层的纠正。发现好像解决了,其实还是不行,测试还是发现问题,对于单伸长还有问题,之后又是修改…………

最后发现……这里就不说了,就是自己要探索啦。

总结

最后我才发现了那个完善的纠正算法,就是代码了的。大家可以在我的github中找到我之前的TreeView中的那个位置算法探索。欢迎大家支持:https://github.com/owant/TreeView

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-08-20 15:28:59

Android树形控件绘制方法的相关文章

Android树形控件的实现方法

在PC上我们已经习惯了树形控件,因为其可以清晰的展现各个节点之间的层次结果,但是在Android平台上,系统并没有提供这样一个控件,而是只有ListView.不过通过改写与ListView绑定的Adapter可以实现这样一个效果. 一个ListView需要和一个Adapter绑定,用于管理数据.在这里以BaseAdapter为例,继承Adapter需要重写四个函数,其中较为重要的是两个:    1 public int getCount()://该函数返回ListView 的ListItem的条

Bootstrap树形控件使用方法详解_javascript技巧

一.JQuery树形控件Jquery树形控件是一款基于JQuery+bootstrap.完全通过js和样式手写出来的非常轻量级的控件,网上很多地方都能看到它的影子.它功能简单.用户体验不错.对于一些简单的层级关系展示比较实用,但对于节点的增删改实现起来就不容易了,如果非要做,可能需要自己去封装. 1.一睹初容 全部收起 展开一级 全部展开 2.代码示例 此控件实现起来也非常简单,只需要引用jQuery和bootstrap组件即可. <link href="~/Content/Tree1/c

Android拆轮子系列之写验证码控件的方法_Android

前言 先看看效果 怎么样不错吧?别急下面我就一步一步的教你实现. 用到的知识点总结: 1.Canvas和pint的使用,我们用它画点,线,字 2.View的基本用法 其实做这个东西还是很简单的,总体思路步骤如下: 1.准备一个Canvas. 2.向Canvas里面画几条斜杠. 3.向canvas里面画100个小点. 4.随机生成4个数字,然后画在canvas里面. 其实就是这么简单,没什么深奥的. 开始写编码 1.首先我们要重写View 既然我们要画验证码,那么我们就需要准备画笔(paint)和

在Android上实现树形控件

  在PC上我们已经习惯了树形控件,因为其可以清晰的展现各个节点之间的层次结果,但是在Android平台上,系统并没有提供这样一个控件,而是只有ListView.不过通过改写改写与ListView绑定的Adapter可以实现这样一个效果.   一个ListView需要和一个Adapter绑定,用于管理数据.在这里以BaseAdapter为例,继承Adapter需要重写四个函数,其中较为重要的是两个:    1 public int getCount()://该函数返回ListView 的List

Android拆轮子系列之写验证码控件的方法

前言 先看看效果 怎么样不错吧?别急下面我就一步一步的教你实现. 用到的知识点总结: 1.Canvas和pint的使用,我们用它画点,线,字 2.View的基本用法 其实做这个东西还是很简单的,总体思路步骤如下: 1.准备一个Canvas. 2.向Canvas里面画几条斜杠. 3.向canvas里面画100个小点. 4.随机生成4个数字,然后画在canvas里面. 其实就是这么简单,没什么深奥的. 开始写编码 1.首先我们要重写View 既然我们要画验证码,那么我们就需要准备画笔(paint)和

Android TextView控件文字添加下划线的实现方法_Android

如下所示: TextView tv = (TextView) findViewById(R.id.text); tv.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); tv.setText("添加下划线"); 以上就是小编为大家带来的Android TextView控件文字添加下划线的实现方法的全部内容了,希望对大家有所帮助,多多支持~ 以上是小编为您精心准备的的内容,在的博客.问答.公众号.人物.课程等栏目也有的相关内容,欢迎继续使用右上

图片-Android要实现这种类似ViewPager左右切换功能应该用什么控件或者方法

问题描述 Android要实现这种类似ViewPager左右切换功能应该用什么控件或者方法 有什么开源项目或者方法实现这种功能么? 解决方案 JazzyViewPager github上有,他有多重效果,你可以改造一下 解决方案二: Android使用ViewPager实现左右切换(转)Android使用ViewPager实现左右切换02(转)android viewpager 实现左右无限循环---------------------- 解决方案三: tabhost可以试试 解决方案四: Ga

vc++-vc6 树形控件读取并绘制的问题

问题描述 vc6 树形控件读取并绘制的问题 我有一些无序带节点名的数据 比如 1,22,3,=a 1,22,4,=b 1,33,5,=c 1,22,6,=d 要写成这样的 该怎么写算法啊,主要是判断父节点有无和指针的问题 解决方案 CString * CTreeappDlg::SplitString(CString str, char split, int& iSubStrs) { int iPos = 0; //分割符位置 int iNums = 0; //分割符的总数 CString str

Android基础控件(EditView、SeekBar等)的使用方法_Android

 android提供了大量的UI控件,本文将介绍TextView.ImageView.Button.EditView.ProgressBar.SeekBar.ScrollView.WebView的使用方法.在介绍各种控件之前,先简单介绍android UI控件最基本的几种属性: id: id是控件唯一标识符,可通过**findViewById(R.id.*)**操作控件. layout_width:控件宽度,可设置为match_parent(充满父布局,即让父布局决定当前控件的宽度).wrap_