当前位置: 移动技术网 > IT编程>移动开发>Android > Android UI 之实现多级树形列表TreeView示例

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

洪震南,涂料招聘网,i589驱动

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

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

先来看一下效果:

然后大体说一下思路:

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

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

下载地址:

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网