自己实现的android树控件treeview
1.开发原因
在项目中经常需要一个需要一个树状框架,这是非常常见的控件。不过可能是谷歌考虑到android是手机系统,界面宽度有限,所以只提供了只有二级的expandablelistview。虽然这个控件可以满足很多需求,但是无数级的树在某些情况下还是需要的,所以我花了一天时间(大部分时间都在调试动画去了,不过现在动画还有点问题,具体原因不明。。如果某位大神能找到原因灰常感谢)。
2.原理
网上很多都是扩展listview实现的,不过listview貌似不支持复杂控件的事件?而且做动画也不方便,所有我决定扩展linearlayout,在里面增加子节点的方式实现。
3.代码
treeview.java:
package net.memornote.android.ui.view;
import java.util.arraylist;
import java.util.list;
import java.util.timer;
import java.util.timertask;
import android.content.context;
import android.graphics.rect;
import android.util.attributeset;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.animation.animationlistener;
import android.view.animation.scaleanimation;
import android.view.animation.translateanimation;
import android.widget.linearlayout;
public class treeview extends linearlayout{
// private list<treeitem> items;
private list<treeitem> sorteditems;
private int animtime;
public treeview(context context, attributeset attrs) {
super(context, attrs);
setorientation(linearlayout.vertical);
}
/**
* initialize data,you must make sure that each item has parent except the top ones.
* @param items the data to show
* @param index the index of the tree to insert to
* @param viewheight each view's height
* @param animtime if you want expand animation,
* you can set the time(ms) of animation,otherwise you can set 0.
*
*/
public void initdata(list<treeitem> items,int index){
if(items==null||items.size()==0){
return ;
}
sortitemlist(items);
int size=sorteditems.size();
initaddindex=index<0?-integer.max_value:index;
for (int i=0;i<size;i++) {
treeitem item=sorteditems.get(i);
recuseshow(item);
}
}
private boolean isanim=false;
/**
* 这个方法还有很 严重的bug,无法使用。。
* 设置为0则关闭动画
* @param animtime
*/
public void enabledanim(int animtime) {
if(animtime<0){
isanim=false;
return ;
}
this.animtime=animtime;
isanim=true;
}
private int initaddindex;
private void recuseshow(treeitem item){
view view=item.getview();
addview(view,initaddindex);
if(item.getparent()!=null){
view.setvisibility(view.gone);
item.isshow=false;
}else {
view.setvisibility(view.visible);
item.isshow=true;
}
initaddindex++;
list<treeitem> childrens=item.getchildrens();
if(childrens.size()>0){
for (treeitem it : childrens) {
recuseshow(it);
}
}
}
@override
public void onwindowfocuschanged(boolean haswindowfocus) {
super.onwindowfocuschanged(haswindowfocus);
if(haswindowfocus){
}
}
private void sortitemlist(list<treeitem> items) {
//把items按照层级关系存放,sorteditems只存放顶层的item
sorteditems=new arraylist<treeitem>(5);
for (treeitem item : items) {
if(item.getparent()==null){
sorteditems.add(item);
}else {
item.getparent().getchildrens().add(item);
}
}
}
private int viewindex=0;
private int animheight=0;
private void addchild(treeitem item,boolean isrecurse){
if(item.getchildrens().size()>0){
list<treeitem> list=item.getchildrens();
for (treeitem it : list) {
view view=it.getview();
if(it.isshow){
continue;
}
viewindex++;
view.setvisibility(view.visible);
it.isshow=true;
if(isanim){
animheight-=it.getviewheight();
}
it.nextisexpand=true;
if(isrecurse){
addchild(it,true);
}
}
}
}
private int removecount=0;
private synchronized void removechild(treeitem item,boolean isrecurse){
if(item.getchildrens().size()>0){
list<treeitem> list=item.getchildrens();
for (treeitem it : list) {
view view=it.getview();
if(!it.isshow){
continue;
}
// removeviewat(viewindex);
translateanimation ta=new translateanimation(0, 0, 0, 0);
ta.setfillafter(true);
ta.setduration(1000);
view.startanimation(ta);
// viewindex++;
removecount++;
it.isshow=false;
view.setvisibility(view.gone);
if(isanim){
animheight+=it.getviewheight();
}
if(isrecurse){
removechild(it,true);
}
}
}
}
private void animadd(){
translateanimation ta=new translateanimation(
animation.absolute, 0,
animation.absolute, 0,
animation.absolute, animheight,
animation.absolute, 0);
ta.setfillbefore(true);
// ta.setfillafter(false);
ta.setduration(animtime);
for (int i = viewindex+1; i < getchildcount(); i++) {
view view=getchildat(i);
view.startanimation(ta);
}
animheight=0;
}
private void animremove(){
translateanimation ta=new translateanimation(
animation.absolute, 0,
animation.absolute, 0,
animation.absolute, animheight,
animation.absolute, 0);
ta.setfillafter(false);
ta.setfillbefore(true);
ta.setduration(animtime);
int startanimindex;
startanimindex=viewindex+1;
for (int i = startanimindex; i < getchildcount(); i++) {
view view=getchildat(i);
view.startanimation(ta);
}
animheight=0;
}
public void expand(treeitem item){
viewindex=indexofchild(item.getview());
addchild(item,false);
if(isanim){
animadd();
}
}
public void expandallchildren(treeitem item) {
viewindex=indexofchild(item.getview());
addchild(item,true);
if(isanim){
animadd();
}
}
public void expandall(){
if(sorteditems==null){
return ;
}
for (treeitem item : sorteditems) {
expandallchildren(item);
}
}
public void contractallchildren(treeitem item) {
viewindex=indexofchild(item.getview())+1;
removechild(item,true);
if(isanim){
animremove();
}
}
public void contractall(){
if(sorteditems==null){
return ;
}
for (treeitem item : sorteditems) {
contractallchildren(item);
}
}
public void bind(treeitem item) {
if(item.nextisexpand){
expand(item);
}else {
contractallchildren(item);
}
item.nextisexpand=!item.nextisexpand;
}
}
treeitem.java
package net.memornote.android.ui.view;
import java.util.arraylist;
import java.util.list;
import android.view.view;
public class treeitem {
private view view;
private treeitem parent;
private list<treeitem> childrens=new arraylist<treeitem>(0);
public boolean nextisexpand=true;
public boolean isshow=false;
private int viewheight;
public treeitem(){}
public treeitem(int id,view view, treeitem parent) {
super();
this.view = view;
this.parent = parent;
}
public view getview() {
if(view!=null){
view.setpadding(getlevel()*20,0,0,0);
}
return view;
}
public void setview(view view) {
this.view = view;
}
public treeitem getparent() {
return parent;
}
public void setparent(treeitem parent) {
this.parent = parent;
}
/**
* 动态获取该节点的级数
* @return
*/
public int getlevel() {
int level=0;
treeitem localparent=parent;
while (localparent!=null) {
level++;
localparent=localparent.getparent();
}
return level;
}
public list<treeitem> getchildrens() {
return childrens;
}
public int getviewheight() {
if(view==null||view.getheight()==0){
return viewheight;
}
return view.getheight();
}
public void setviewheight(int viewheight) {
this.viewheight = viewheight;
}
}
测试代码:
package net.memornote.android.ui;
import net.memornote.android.r;
import net.memornote.android.ui.fragment.mainfragment;
import net.memornote.android.ui.fragment.menufragment;
import com.actionbarsherlock.view.menu;
import com.jeremyfeinstein.slidingmenu.lib.slidingmenu;
import com.jeremyfeinstein.slidingmenu.lib.app.slidingfragmentactivity;
import android.os.bundle;
import android.view.keyevent;
public class mainactivity extends slidingfragmentactivity {
@override
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.slid_content_frame);
tv_notebook=(treeview) findviewbyid(r.id.tv_notebook);
list<treeitem> items=new arraylist<treeitem>();
initdata(items);
tv_notebook.initdata(items, 0);
tv_notebook.enabledanim(500);
}
//初始化一些测试数据
public void initdata(list<treeitem> items) {
for (int i=0;i<10;i++) {
// textview tv=new textview(getactivity());
button button=new button(getactivity());
button.settext("item"+i);
final treeitem item=new treeitem(0, button, null);
button.setonclicklistener(new onclicklistener() {
@override
public void onclick(view v) {
tv_notebook.bind(item);
}
});
items.add(item);
if(i%2==0){
button bt1=new button(getactivity());
bt1.settext("item"+i);
bt1.setclickable(true);
final treeitem item_1=new treeitem(0, bt1, null);
bt1.setonclicklistener(new onclicklistener() {
@override
public void onclick(view v) {
tv_notebook.bind(item_1);
}
});
item_1.setparent(item);
items.add(item_1);
if(i%4==0){
button bt_2=new button(getactivity());
bt_2.settext("item"+i);
bt_2.setclickable(true);
final treeitem item_2=new treeitem(0, bt_2, null);
bt_2.setonclicklistener(new onclicklistener() {
@override
public void onclick(view v) {
tv_notebook.bind(item_2);
}
});
item_2.setparent(item_1);
items.add(item_2);
}
}
}
}
@override
public boolean oncreateoptionsmenu(menu menu) {
return true;
}
}
上一篇: C#递归算法之快速排序
下一篇: 详细介绍Android中回调函数机制