学习(四)自定义多级树形列表

来源:互联网 发布: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>


好了,所有的准备工作我们都做完了,编译下看看效果吧,哈哈。

最后欢迎大家指正!!!!!




0 0
原创粉丝点击