欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android UI 之实现多级树形列表TreeView示例

程序员文章站 2024-02-10 18:33:40
所谓treeview就是在windows中常见的多级列表树,在android中系统只默认提供了listview和expandablelistview两种列表,最多只支持到二...

所谓treeview就是在windows中常见的多级列表树,在android中系统只默认提供了listview和expandablelistview两种列表,最多只支持到二级列表的实现,所以如果想要实现三级和更多层次的列表,就需要我们自己来做一些处理了。

其实这个效果很久以前就有人想办法实现了,但是实现的效果有一些问题,我的实现思路主要也是来自于网络,但是在其基础上修正了逻辑上的一些错误,做了一些优化。

先来看一下效果:

Android UI 之实现多级树形列表TreeView示例

然后大体说一下思路:

其实这里实现的多级列表只是一个视觉效果,我们看到的分级效果是由于每行的缩进不同造成的。比如在上面的效果中,山东省和广东省是级别最高的层次,山东省下的青岛市作为山东省的子项,我们增加他的左缩进,这样看起来就有了层次感了。其他的层次也是同理。

也就是说,我们只用了一个listview,工作的重点就在于不断变化listview显示的数据,根据用户的操作,将数据修改为用户想要看到的数据内容,并根据每个数据项的不同,在显示效果上做不同的缩进处理,最终呈现出一个treeview的效果。

具体的实现思路参考下面的项目结构和具体代码:

Android UI 之实现多级树形列表TreeView示例

element.java:

package com.example.androidtreeviewdemo.treeview; 
/** 
 * element类 
 * @author carrey 
 * 
 */ 
public class element { 
  /** 文字内容 */ 
  private string contenttext; 
  /** 在tree中的层级 */ 
  private int level; 
  /** 元素的id */ 
  private int id; 
  /** 父元素的id */ 
  private int parendid; 
  /** 是否有子元素 */ 
  private boolean haschildren; 
  /** item是否展开 */ 
  private boolean isexpanded; 
   
  /** 表示该节点没有父元素,也就是level为0的节点 */ 
  public static final int no_parent = -1; 
  /** 表示该元素位于最顶层的层级 */ 
  public static final int top_level = 0; 
   
  public element(string contenttext, int level, int id, int parendid, 
      boolean haschildren, boolean isexpanded) { 
    super(); 
    this.contenttext = contenttext; 
    this.level = level; 
    this.id = id; 
    this.parendid = parendid; 
    this.haschildren = haschildren; 
    this.isexpanded = isexpanded; 
  } 
 
  public boolean isexpanded() { 
    return isexpanded; 
  } 
 
  public void setexpanded(boolean isexpanded) { 
    this.isexpanded = isexpanded; 
  } 
 
  public string getcontenttext() { 
    return contenttext; 
  } 
 
  public void setcontenttext(string contenttext) { 
    this.contenttext = contenttext; 
  } 
 
  public int getlevel() { 
    return level; 
  } 
 
  public void setlevel(int level) { 
    this.level = level; 
  } 
 
  public int getid() { 
    return id; 
  } 
 
  public void setid(int id) { 
    this.id = id; 
  } 
 
  public int getparendid() { 
    return parendid; 
  } 
 
  public void setparendid(int parendid) { 
    this.parendid = parendid; 
  } 
 
  public boolean ishaschildren() { 
    return haschildren; 
  } 
 
  public void sethaschildren(boolean haschildren) { 
    this.haschildren = haschildren; 
  } 
} 

treeviewadapter.java:

package com.example.androidtreeviewdemo.treeview; 
 
import java.util.arraylist; 
 
import com.example.androidtreeviewdemo.r; 
 
import android.view.layoutinflater; 
import android.view.view; 
import android.view.viewgroup; 
import android.widget.baseadapter; 
import android.widget.imageview; 
import android.widget.textview; 
/** 
 * treeviewadapter 
 * @author carrey 
 * 
 */ 
public class treeviewadapter extends baseadapter { 
  /** 元素数据源 */ 
  private arraylist<element> elementsdata; 
  /** 树中元素 */ 
  private arraylist<element> elements; 
  /** layoutinflater */ 
  private layoutinflater inflater; 
  /** item的行首缩进基数 */ 
  private int indentionbase; 
   
  public treeviewadapter(arraylist<element> elements, arraylist<element> elementsdata, layoutinflater inflater) { 
    this.elements = elements; 
    this.elementsdata = elementsdata; 
    this.inflater = inflater; 
    indentionbase = 50; 
  } 
   
  public arraylist<element> getelements() { 
    return elements; 
  } 
   
  public arraylist<element> getelementsdata() { 
    return elementsdata; 
  } 
   
  @override 
  public int getcount() { 
    return elements.size(); 
  } 
 
  @override 
  public object getitem(int position) { 
    return elements.get(position); 
  } 
 
  @override 
  public long getitemid(int position) { 
    return position; 
  } 
 
  @override 
  public view getview(int position, view convertview, viewgroup parent) { 
    viewholder holder = null; 
    if (convertview == null) { 
      holder = new viewholder(); 
      convertview = inflater.inflate(r.layout.treeview_item, null); 
      holder.disclosureimg = (imageview) convertview.findviewbyid(r.id.disclosureimg); 
      holder.contenttext = (textview) convertview.findviewbyid(r.id.contenttext); 
      convertview.settag(holder); 
    } else { 
      holder = (viewholder) convertview.gettag(); 
    } 
    element element = elements.get(position); 
    int level = element.getlevel(); 
    holder.disclosureimg.setpadding( 
        indentionbase * (level + 1),  
        holder.disclosureimg.getpaddingtop(),  
        holder.disclosureimg.getpaddingright(),  
        holder.disclosureimg.getpaddingbottom()); 
    holder.contenttext.settext(element.getcontenttext()); 
    if (element.ishaschildren() && !element.isexpanded()) { 
      holder.disclosureimg.setimageresource(r.drawable.close); 
      //这里要主动设置一下icon可见,因为convertview有可能是重用了"设置了不可见"的view,下同。 
      holder.disclosureimg.setvisibility(view.visible); 
    } else if (element.ishaschildren() && element.isexpanded()) { 
      holder.disclosureimg.setimageresource(r.drawable.open); 
      holder.disclosureimg.setvisibility(view.visible); 
    } else if (!element.ishaschildren()) { 
      holder.disclosureimg.setimageresource(r.drawable.close); 
      holder.disclosureimg.setvisibility(view.invisible); 
    } 
    return convertview; 
  } 
   
  /** 
   * 优化holder 
   * @author carrey 
   * 
   */ 
  static class viewholder{ 
    imageview disclosureimg; 
    textview contenttext; 
  } 
} 

treeviewitemclicklistener.java:

package com.example.androidtreeviewdemo.treeview; 
 
import java.util.arraylist; 
 
import android.view.view; 
import android.widget.adapterview; 
import android.widget.adapterview.onitemclicklistener; 
/** 
 * treeview item点击事件 
 * @author carrey 
 * 
 */ 
public class treeviewitemclicklistener implements onitemclicklistener { 
  /** adapter */ 
  private treeviewadapter treeviewadapter; 
   
  public treeviewitemclicklistener(treeviewadapter treeviewadapter) { 
    this.treeviewadapter = treeviewadapter; 
  } 
   
  @override 
  public void onitemclick(adapterview<?> parent, view view, int position, 
      long id) { 
    //点击的item代表的元素 
    element element = (element) treeviewadapter.getitem(position); 
    //树中的元素 
    arraylist<element> elements = treeviewadapter.getelements(); 
    //元素的数据源 
    arraylist<element> elementsdata = treeviewadapter.getelementsdata(); 
     
    //点击没有子项的item直接返回 
    if (!element.ishaschildren()) { 
      return; 
    } 
     
    if (element.isexpanded()) { 
      element.setexpanded(false); 
      //删除节点内部对应子节点数据,包括子节点的子节点... 
      arraylist<element> elementstodel = new arraylist<element>(); 
      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.setexpanded(true); 
      //从数据源中提取子节点数据添加进树,注意这里只是添加了下一级子节点,为了简化逻辑 
      int i = 1;//注意这里的计数器放在for外面才能保证计数有效 
      for (element e : elementsdata) { 
        if (e.getparendid() == element.getid()) { 
          e.setexpanded(false); 
          elements.add(position + i, e); 
          i ++; 
        } 
      } 
      treeviewadapter.notifydatasetchanged(); 
    } 
  } 
 
} 

mainactivity.java:

package com.example.androidtreeviewdemo; 
 
import java.util.arraylist; 
 
import com.example.androidtreeviewdemo.treeview.element; 
import com.example.androidtreeviewdemo.treeview.treeviewadapter; 
import com.example.androidtreeviewdemo.treeview.treeviewitemclicklistener; 
 
import android.os.bundle; 
import android.app.activity; 
import android.content.context; 
import android.view.layoutinflater; 
import android.view.menu; 
import android.widget.listview; 
 
public class mainactivity extends activity { 
  /** 树中的元素集合 */ 
  private arraylist<element> elements; 
  /** 数据源元素集合 */ 
  private arraylist<element> elementsdata; 
   
  @override 
  protected void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.activity_main); 
     
    layoutinflater inflater = (layoutinflater) getsystemservice(context.layout_inflater_service); 
     
    init(); 
     
    listview treeview = (listview) findviewbyid(r.id.treeview); 
    treeviewadapter treeviewadapter = new treeviewadapter( 
        elements, elementsdata, inflater); 
    treeviewitemclicklistener treeviewitemclicklistener = new treeviewitemclicklistener(treeviewadapter); 
    treeview.setadapter(treeviewadapter); 
    treeview.setonitemclicklistener(treeviewitemclicklistener); 
  } 
   
  private void init() { 
    elements = new arraylist<element>(); 
    elementsdata = new arraylist<element>(); 
     
    //添加节点 -- 节点名称,节点level,节点id,父节点id,是否有子节点,是否展开 
     
    //添加最外层节点 
    element e1 = new element("山东省", element.top_level, 0, element.no_parent, true, false); 
     
    //添加第一层节点 
    element e2 = new element("青岛市", element.top_level + 1, 1, e1.getid(), true, false); 
    //添加第二层节点 
    element e3 = new element("市南区", element.top_level + 2, 2, e2.getid(), true, false); 
    //添加第三层节点 
    element e4 = new element("香港中路", element.top_level + 3, 3, e3.getid(), false, false); 
     
    //添加第一层节点 
    element e5 = new element("烟台市", element.top_level + 1, 4, e1.getid(), true, false); 
    //添加第二层节点 
    element e6 = new element("芝罘区", element.top_level + 2, 5, e5.getid(), true, false); 
    //添加第三层节点 
    element e7 = new element("凤凰台街道", element.top_level + 3, 6, e6.getid(), false, false); 
     
    //添加第一层节点 
    element e8 = new element("威海市", element.top_level + 1, 7, e1.getid(), false, false); 
     
    //添加最外层节点 
    element e9 = new element("广东省", element.top_level, 8, element.no_parent, true, false); 
    //添加第一层节点 
    element e10 = new element("深圳市", element.top_level + 1, 9, e9.getid(), true, false); 
    //添加第二层节点 
    element e11 = new element("南山区", element.top_level + 2, 10, e10.getid(), true, false); 
    //添加第三层节点 
    element e12 = new element("深南大道", element.top_level + 3, 11, e11.getid(), true, false); 
    //添加第四层节点 
    element e13 = new element("10000号", element.top_level + 4, 12, e12.getid(), false, false); 
     
    //添加初始树元素 
    elements.add(e1); 
    elements.add(e9); 
    //创建数据源 
    elementsdata.add(e1); 
    elementsdata.add(e2); 
    elementsdata.add(e3); 
    elementsdata.add(e4); 
    elementsdata.add(e5); 
    elementsdata.add(e6); 
    elementsdata.add(e7); 
    elementsdata.add(e8); 
    elementsdata.add(e9); 
    elementsdata.add(e10); 
    elementsdata.add(e11); 
    elementsdata.add(e12); 
    elementsdata.add(e13); 
  } 
 
  @override 
  public boolean oncreateoptionsmenu(menu menu) { 
    // inflate the menu; this adds items to the action bar if it is present. 
    getmenuinflater().inflate(r.menu.activity_main, menu); 
    return true; 
  } 
 
} 

treeview_item.xml:

<?xml version="1.0" encoding="utf-8"?> 
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" > 
   
  <imageview  
    android:id="@+id/disclosureimg" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centervertical="true" 
    android:layout_alignparentleft="true"/> 
   
  <textview  
    android:id="@+id/contenttext" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_centervertical="true" 
    android:layout_torightof="@id/disclosureimg"/> 
 
</relativelayout> 

activity_main.xml:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  tools:context=".mainactivity" > 
 
  <listview  
    android:id="@+id/treeview" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 
 
</relativelayout> 

下载地址:androidtreeviewdemo_jb51.rar

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