学习(四)自定义多级树形列表
来源:互联网 发布:mac ps添加字体 编辑:程序博客网 时间:2024/05/22 01:49
自定义多极树形列表:可实现无限级树形结构的显示,其实现原理就是利用了android当中的ListView控件,在ListView当中,不断的插入和删除数据,以及给后插入的数据加上缩进,造成一种类似于树形结构的假象,其本质就是一个ListView;
先放上3张运行效果图,接下来再讲实现的具体步骤
:
好了,接下来讲具体实现.
步骤一:我们先来定义下树节点的结构
public class TreeElement {
private Stringtitle; // 章节文本
private Stringvalue; //
private Stringicon; // 加载图片的序号
private Stringknowledge_id;// 知识点id(用来判断是否是叶子节点)
privateint level; // 在tree中的层级
private BooleanhasChildren; // 是否有子节点
private BooleanisExpanded; // item是否展开
private List<TreeElement>childTreeList; //子结点列表
}这里重点要解释的是 level 这个变量,level 是用了标示当前节点所在整个树结构里的层级,什么意思呢,看第3张图,“第一章”“第二章”“第三章”“第四章”位于第0层,也就是level=0,"整式的加减"及其兄弟节点位于第1层level=1,以此类推,“整式加减的运算法则”level=2.........
数据结构定义完之后,我们接下来进入第二步
步骤二:我们定义一个继承自BaseAdapter的AdapterView,下面看具体代码
public class TreeViewAdapterextends BaseAdapter {
/** 元素数据源 */
private ArrayList<TreeElement>elementsData;
/** 树中元素 */
private ArrayList<TreeElement>elements;
/** LayoutInflater */
private LayoutInflaterinflater;
/** item的行首缩进基数 */
privateint indentionBase;
public TreeViewAdapter() {
// TODO Auto-generated constructor stub
super();
}
public TreeViewAdapter(ArrayList<TreeElement> elements,
ArrayList<TreeElement> elementsData, LayoutInflater inflater) {
this.elements = elements;
this.elementsData = elementsData;
this.inflater = inflater;
indentionBase = 50;
}
public ArrayList<TreeElement> getElements() {
returnelements;
}
public ArrayList<TreeElement> getElementsData() {
returnelementsData;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return elements.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return elements.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if( convertView ==null )
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.study_treeview_item,null);
holder.disclosureImg = (ImageView)convertView.findViewById(R.id.treeitemimage);
holder.contentText = (TextView)convertView.findViewById(R.id.treeitemtitle);
convertView.setTag(holder);
}
else{
holder = (ViewHolder)convertView.getTag();
}
TreeElement element = elements.get(position);
int level = element.getLevel();
holder.disclosureImg.setPadding(
indentionBase * level,
holder.disclosureImg.getPaddingTop(),
holder.disclosureImg.getPaddingRight(),
holder.disclosureImg.getPaddingBottom());
holder.contentText.setText(element.getTitle());
if (element.getHasChildren() && !element.getIsExpanded()) {
holder.disclosureImg.setImageResource(R.drawable.close);
//这里要主动设置一下icon可见,因为convertView有可能是重用了"设置了不可见"的view,下同。
holder.disclosureImg.setVisibility(View.VISIBLE);
} else if (element.getHasChildren() && element.getIsExpanded()) {
holder.disclosureImg.setImageResource(R.drawable.open);
holder.disclosureImg.setVisibility(View.VISIBLE);
} else if (!element.getHasChildren()) {
holder.disclosureImg.setImageResource(R.drawable.close);
holder.disclosureImg.setVisibility(View.INVISIBLE);
}
return convertView;
}
static class ViewHolder {
ImageView disclosureImg;
TextView contentText;
}
}
这里需要解释的是
1. elementsData:就是从服务器上获取的全部的数据
2.elements:这个要重点解释一下,这个变量是用来实现树结构最重要,最核心的一个数据源,首先最开始它存放的是根节点的全部子结点数据,也就是图上的第一章,第二章,第三章,第四章,这四个数据,当我们每点击一下屏幕上的节点,我们就会往这个变量里面插入和删除当前节点的子结点数据,这下明白了吧,哈哈哈哈
3.indentionBase:这个就是子节点相对于父节点的缩进量。
第三步:我们实现一个自定义的监听类
public class TreeViewItemClickListenerimplements OnItemClickListener {
/** adapter */
private TreeViewAdaptertreeViewAdapter;
private Contextcontext;
public TreeViewItemClickListener(Context context,TreeViewAdapter treeViewAdapter) {
this.treeViewAdapter = treeViewAdapter;
this.context = context;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// //点击的item代表的元素
TreeElement element = (TreeElement) treeViewAdapter.getItem(position);
//树中的元素
ArrayList<TreeElement> elements = treeViewAdapter.getElements();
//元素的数据源
ArrayList<TreeElement> elementsData = treeViewAdapter.getElementsData();
//点击没有子项的item直接返回
if (!element.getHasChildren()) {
Intent intent = new Intent(context, StudyKnowledgeActivity.class);
Bundle bundle = new Bundle();
bundle.putString("title", element.getTitle());
bundle.putString("value", element.getValue());
intent.putExtra("knowledge", bundle);
context.startActivity(intent);
return;
}
if (element.getIsExpanded()) {
element.setIsExpanded(false);
//删除节点内部对应子节点数据,包括子节点的子节点...
ArrayList<TreeElement> elementsToDel = new ArrayList<TreeElement>();
for (int i = position + 1; i < elements.size(); i++) {
if (element.getLevel() >= elements.get(i).getLevel())
break;
elementsToDel.add(elements.get(i));
}
elements.removeAll(elementsToDel);
treeViewAdapter.notifyDataSetChanged();
} else {
element.setIsExpanded(true);
for(int i = 0; i < element.getChildTreeList().size(); i++)
{
elements.add(position+1, element.getChildTreeList().get(i));
}
treeViewAdapter.notifyDataSetChanged();
}
}
}
这里主要的操作就是elements.add 和 elements.removeAll这两个地方第四步;具体使用,看代码吧
initdata();
LayoutInflater inflater = (LayoutInflater)getSystemService(this.LAYOUT_INFLATER_SERVICE);
treeViewAdapter =new TreeViewAdapter(elements,elementsData, inflater);
treeView = (ListView)findViewById(R.id.listView);
treeView.setAdapter(treeViewAdapter);
TreeViewItemClickListener listener = new TreeViewItemClickListener(StudyActivity.this,treeViewAdapter);
treeView.setOnItemClickListener(listener);
这里无过多解释,大家一看就会明白是做什么的,需要解释的就是 initdata() ,怎么会出现这么一个奇怪的东西,接下来就开始讲它
第五步:xml的解析.这里使用的是dom解析方式,我试过sax和pull解析,这两种解析方式都没能达到我想要的效果,可能是我还不是很熟悉的缘故吧,哈,废话不多说了,上码
private void initdata() {
try {
InputStream is = this.getAssets().open("newfile1.xml");
TreeElementDomParser domParser = new TreeElementDomParser();
domParser.parse(is);
elementsData = (ArrayList<TreeElement>) domParser.getTreeElementList();
int dataCount =elementsData.size();
for(int i = 0; i < dataCount; i++)
{
TreeElement element = elementsData.get(i);
elements.add(i, element);
}
} catch (Exception e) {
// TODO: handle exception
}
}
我把xml文件存到本地assets文件夹下,用来模仿从服务器获取下来的数据,我们看一下TreeElementDomParser类public class TreeElementDomParser {
private List<TreeElement>treeElementList = null;
privateint level;//层级
public TreeElementDomParser()
{
super();
treeElementList =new ArrayList<TreeElement>();
}
public List<TreeElement> getTreeElementList() {
returntreeElementList;
}
public void setTreeElementList(List<TreeElement> treeElementList) {
this.treeElementList = treeElementList;
}
public void parse(InputStream is) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
level = -1;
try{
DocumentBuilder builder = factory.newDocumentBuilder();
org.w3c.dom.Document doc = builder.parse(is);
Element rootElement = doc.getDocumentElement();
NodeList nodeList = rootElement.getChildNodes();
parserNode(treeElementList,nodeList,null);
}catch(Exception e){
e.printStackTrace();
}
}
private void parserNode(List<TreeElement> treeElementList, NodeList nodeList, TreeElement parentElement)
{
List<TreeElement> elementList_in = treeElementList;
NodeList tempNodeList = nodeList;
int childNodeCount = tempNodeList.getLength();
level++;
for(int i = 0; i < childNodeCount; i++)
{
Node childElement = tempNodeList.item(i);
String nodeName = childElement.getNodeName();
if(nodeName.equals("treeNode"))
{
TreeElement treeElement = new TreeElement();;
NodeList childList = null;
String title = null;
String value = null;
String icon = null;
String knowledge_id = null;
Boolean hasAttributes = childElement.hasAttributes();
if(hasAttributes)
{
NamedNodeMap nodeMap = childElement.getAttributes();
title = nodeMap.getNamedItem("title").getNodeValue();
if(nodeMap.getLength() > 1)
{
value = nodeMap.getNamedItem("value").getNodeValue();
icon = nodeMap.getNamedItem("icon").getNodeValue();
knowledge_id = nodeMap.getNamedItem("knowledge_id").getNodeValue();
}
}
treeElement.setTitle(title);
treeElement.setValue(value);
treeElement.setIcon(icon);
treeElement.setKnowledge_id(knowledge_id);
treeElement.setLevel(level);
treeElement.setParentElement(parentElement);
Boolean hasChildNodes = childElement.hasChildNodes();
if(hasChildNodes)
{
List<TreeElement> tempElementList = new ArrayList<TreeElement>();
childList = childElement.getChildNodes();
treeElement.setChildTreeList(tempElementList);
//从这里递归
parserNode(tempElementList,childList,treeElement);
}
else{
treeElement.setChildTreeList(null);
}
treeElement.setHasChildren(hasChildNodes);
treeElement.setIsExpanded(false);
elementList_in.add(treeElement);
}
}
level--;
}
}
解释下level++和level--,我们看下level的位置,放在这里是因为我们每次递归子节点的时候可以确定子结点的层级,当我们回溯回父节点,它又可以确定父节点的层级,其他的无需过多解释了,下面付上一个xml的结构<tree>
<treeNodetitle='第一章 有理数'>
<treeNodetitle='有理数-导语'value='9176'icon='2'knowledge_id='6304'></treeNode>
<treeNodetitle='1.1正数和负数'>
<treeNodetitle='正数、负数、0'value='1329'icon='1'knowledge_id='974'></treeNode>
</treeNode>
<treeNodetitle='1.2有理数'>
<treeNodetitle='有理数'value='1331'icon='1'knowledge_id='977'></treeNode>
<treeNodetitle='数轴、原点'value='1334'icon='1'knowledge_id='978'></treeNode>
<treeNodetitle='相反数'value='1339'icon='1'knowledge_id='979'></treeNode>
<treeNodetitle='绝对值'value='1341'icon='1'knowledge_id='981'></treeNode>
<treeNodetitle='比较有理数大小'value='1342'icon='1'knowledge_id='985'></treeNode>
</treeNode>
<treeNodetitle='1.3有理数的加减法'>
<treeNodetitle='有理数加法法则'value='1349'icon='1'knowledge_id='986'></treeNode>
<treeNodetitle='有理数加法运算律'value='1350'icon='1'knowledge_id='988'></treeNode>
<treeNodetitle='有理数的减法'value='1352'icon='1'knowledge_id='998'></treeNode>
</treeNode>
<treeNodetitle='1.4有理数的乘除法'>
<treeNodetitle='有理数乘法法则'value='1354'icon='1'knowledge_id='1000'></treeNode>
<treeNodetitle='有理数的倒数'value='1357'icon='1'knowledge_id='1001'></treeNode>
<treeNodetitle='有理数乘法交换律'value='1359'icon='1'knowledge_id='1002'></treeNode>
<treeNodetitle='有理数乘法结合律'value='1363'icon='1'knowledge_id='1003'></treeNode>
<treeNodetitle='有理数乘法分配律'value='1366'icon='1'knowledge_id='1004'></treeNode>
<treeNodetitle='有理数除法法则'value='1368'icon='1'knowledge_id='1005'></treeNode>
<treeNodetitle='有理数的加减乘除混合运算 'value='1370'icon='1'knowledge_id='1006'></treeNode>
</treeNode>
<treeNodetitle='1.5有理数的乘方'>
<treeNodetitle='有理数的乘方'value='1374'icon='1'knowledge_id='1007'></treeNode>
<treeNodetitle='有乘方的有理数混合运算顺序'value='1375'icon='1'knowledge_id='1011'></treeNode>
<treeNodetitle=' 负a的n次方与负的a的n次方'value='1376'icon='1'knowledge_id='1015'></treeNode>
<treeNodetitle='科学计数法'value='1377'icon='1'knowledge_id='1018'></treeNode>
<treeNodetitle='近似数'value='1384'icon='1'knowledge_id='1019'></treeNode>
</treeNode>
<treeNodetitle='有理数-串讲'value='9177'icon='2'knowledge_id='6303'></treeNode>
</treeNode>
<treeNodetitle='第二章 整式的加减'>
<treeNodetitle='整式的加减-导语'value='9251'icon='2'knowledge_id='5339'></treeNode>
<treeNodetitle='2.1整式'>
<treeNodetitle='单项式'value='1391'icon='1'knowledge_id='1020'></treeNode>
<treeNodetitle='多项式 'value='1392'icon='1'knowledge_id='1022'></treeNode>
<treeNodetitle='同类项'value='1393'icon='1'knowledge_id='1025'></treeNode>
<treeNodetitle='合并同类项'value='1394'icon='1'knowledge_id='1026'></treeNode>
<treeNodetitle='去括号法则'value='1395'icon='2'knowledge_id='1028'></treeNode>
</treeNode>
<treeNodetitle='2.2整式的加减'>
<treeNodetitle='整式加减的运算法则'value='1399'icon='1'knowledge_id='1031'></treeNode>
</treeNode>
<treeNodetitle='整式的加减-串讲'value='9253'icon='2'knowledge_id='5340'></treeNode>
</treeNode>
<treeNodetitle='第三章 一元一次方程'>
<treeNodetitle='一元一次方程-导语'value='9448'icon='2'knowledge_id='6427'></treeNode>
<treeNodetitle='3.1从算式到方程'>
<treeNodetitle='一元一次方程的概念'value='1405'icon='1'knowledge_id='1711'></treeNode>
<treeNodetitle='等式的性质1'value='1407'icon='1'knowledge_id='1033'></treeNode>
<treeNodetitle='等式的性质2'value='1410'icon='1'knowledge_id='1035'></treeNode>
</treeNode>
<treeNodetitle='3.2解一元一次方程(一)'>
<treeNodetitle='解一元一次方程——合并同类项'value='1414'icon='1'knowledge_id='1041'></treeNode>
<treeNodetitle='解一元一次方程——移项'value='1417'icon='1'knowledge_id='1042'></treeNode>
</treeNode>
<treeNodetitle='3.3解一元一次方程(二)'>
<treeNodetitle='解一元一次方程——去括号'value='1426'icon='1'knowledge_id='1044'></treeNode>
<treeNodetitle='解一元一次方程——去分母'value='1431'icon='1'knowledge_id='1050'></treeNode>
</treeNode>
<treeNodetitle='3.4实际问题与一元一次方程'>
<treeNodetitle='实际问题与一元一次方程'value='1437'icon='1'knowledge_id='1053'></treeNode>
</treeNode>
<treeNodetitle='一元一次方程-串讲'value='9449'icon='2'knowledge_id='6428'></treeNode>
</treeNode>
<treeNodetitle='第四章 几何图形初步'>
<treeNodetitle='几何图形初步-导语'value='9488'icon='2'knowledge_id='6431'></treeNode>
<treeNodetitle='4.1几何图形'>
<treeNodetitle='立体图形与平面图形'value='1444'icon='1'knowledge_id='1057'></treeNode>
<treeNodetitle='立体图形到平面图形的转化——从不同方向看'value='1447'icon='1'knowledge_id='1062'></treeNode>
<treeNodetitle='立体图形到平面图形的转化——展开图'value='1450'icon='1'knowledge_id='1065'></treeNode>
<treeNodetitle='点、线、面、体'value='1454'icon='1'knowledge_id='1067'></treeNode>
</treeNode>
<treeNodetitle='4.2直线、射线、线段'>
<treeNodetitle='直线、射线、线段'value='1460'icon='1'knowledge_id='1071'></treeNode>
<treeNodetitle='线段的尺规作图与比较'value='1464'icon='1'knowledge_id='1072'></treeNode>
<treeNodetitle='线段的运算'value='1468'icon='1'knowledge_id='1075'></treeNode>
</treeNode>
<treeNodetitle='4.3角'>
<treeNodetitle='角的定义和表示法'value='1473'icon='1'knowledge_id='1081'></treeNode>
<treeNodetitle='角的度量'value='1476'icon='1'knowledge_id='1084'></treeNode>
<treeNodetitle='角的比较与运算'value='1480'icon='1'knowledge_id='1086'></treeNode>
<treeNodetitle='角的平分线'value='1485'icon='1'knowledge_id='1089'></treeNode>
<treeNodetitle='余角'value='1489'icon='1'knowledge_id='1090'></treeNode>
<treeNodetitle='补角'value='1491'icon='1'knowledge_id='1091'></treeNode>
<treeNodetitle='方位角'value='1493'icon='1'knowledge_id='1092'></treeNode>
</treeNode>
<treeNodetitle='几何图形初步-串讲'value='9602'icon='2'knowledge_id='6433'></treeNode>
</treeNode>
</tree>
好了,所有的准备工作我们都做完了,编译下看看效果吧,哈哈。
最后欢迎大家指正!!!!!
- 学习(四)自定义多级树形列表
- android多级树形列表
- 多级列表的学习:ExpandableListView
- Word文档自定义多级目录列表
- extjs多级树形列表——json传参
- Android多级树形结构列表(理论上可以无限级)
- 更快实现Android多级树形选择列表
- 多级下拉列表(angular)
- 多级树形菜单设计
- ExpandableListView---多级树形菜单
- js树形多级菜单
- 【多级树形菜单-dialog自定义动画弹出方式-手势监听】dialog自定义动画
- 多级列表样式技巧(一)
- JavaScript实现二级、多级(N级)联动下拉列表框更新版(续)- 四级联动的演示
- android中树形json解析为对象,并通过dialog显示,多级列表
- android中树形json解析为对象,并通过dialog显示,多级列表
- Phthon学习笔记(四):生成列表
- 【转】实现新建多级目录(树形)linux-c语言
- 【OpenStack】Nova中的migrate/resize/live-migration
- java基础1
- AngularJs中的延迟加载
- 【你可知乎】大型的支付系统,如支付宝、财付通每天交易额都非常巨大,后系统是如何对账、风控的呢?
- 防火墙的工作原理
- 学习(四)自定义多级树形列表
- android 状态栏操作
- 软件开发人员(程序员)的出路
- Android百度地图实践 文件liblocSDK.so
- IMP-00041: 警告: 创建的对象带有编译警告解决办法
- C语言标准(转自wikipedia)
- android:screenOrientation的说明 固定屏幕显示方向
- 环境变量和自定义变量 与export
- asp.net 未能写入输出文件--“拒绝访问的解决办法