自己實現的android樹控件,android TreeView

1.開發原因

  在項目中經常需要一個需要一個樹狀框架,這是非常常見的控件。不過可能是谷歌考慮到android是手機系統,界面寬度有限,

 

所以隻提供瞭隻有二級的ExpandableListView。雖然這個控件可以滿足很多需求,但是無數級的樹在某些情況下還是需要的,所以我花瞭一天時間

 

(大部分時間都在調試動畫去瞭,不過現在動畫還有點問題,具體原因不明。。如果某位大神能找到原因灰常感謝)。

 

  2.原理

  網上很多都是擴展listview實現的,不過listview貌似不支持復雜控件的事件?而且做動畫也不方便,所有我決定擴展linearlayout,在裡面增加子節點的方式實現。

 

  3.代碼

TreeView.java:

 

 

復制代碼

  1 package net.memornote.android.ui.view;

  2 

  3 import java.util.ArrayList;

  4 import java.util.List;

  5 import java.util.Timer;

  6 import java.util.TimerTask;

  7 

  8 import android.content.Context;

  9 import android.graphics.Rect;

 10 import android.util.AttributeSet;

 11 import android.view.View;

 12 import android.view.animation.Animation;

 13 import android.view.animation.Animation.AnimationListener;

 14 import android.view.animation.ScaleAnimation;

 15 import android.view.animation.TranslateAnimation;

 16 import android.widget.LinearLayout;

 17 

 18 public class TreeView extends LinearLayout{

 19     

 20 //    private List<TreeItem> items;

 21     private List<TreeItem> sortedItems;

 22     private int animTime;

 23 

 24     public TreeView(Context context, AttributeSet attrs) {

 25         super(context, attrs);

 26         setOrientation(LinearLayout.VERTICAL);

 27     }

 28     /**

 29      * initialize data,you must make sure that each item has parent except the top ones.

 30      * @param items the data to show 

 31      * @param index the index of the tree to insert to

 32      * @param viewHeight each view's height

 33      * @param animTime if you want expand animation, 

 34      * you can set the time(ms) of animation,otherwise you can set 0.

 35      * 

 36      */

 37     public void initData(List<TreeItem> items,int index){

 38         

 39         if(items==null||items.size()==0){

 40             return ;

 41         }

 42 

 43         sortItemList(items);

 44         

 45         int size=sortedItems.size();

 46         

 47         initAddIndex=index<0?-Integer.MAX_VALUE:index;

 48         

 49         for (int i=0;i<size;i++) {

 50             TreeItem item=sortedItems.get(i);

 51             recuseShow(item);

 52         }

 53         

 54     }

 55     

 56     private boolean isAnim=false;

 57     /**

 58      * 這個方法還有很 嚴重的bug,無法使用。。

 59      * 設置為0則關閉動畫

 60      * @param animTime

 61      */

 62     public void enabledAnim(int animTime) {

 63         if(animTime<0){

 64             isAnim=false;

 65             return ;

 66         }

 67         this.animTime=animTime;

 68         isAnim=true;

 69     }

 70     

 71     private int initAddIndex; 

 72     

 73     private void recuseShow(TreeItem item){

 74         View view=item.getView();

 75         addView(view,initAddIndex);

 76         if(item.getParent()!=null){

 77             view.setVisibility(View.GONE);

 78             item.isShow=false;

 79         }else {

 80             view.setVisibility(View.VISIBLE);

 81             item.isShow=true;

 82         }

 83         initAddIndex++;

 84         List<TreeItem> childrens=item.getChildrens();

 85         if(childrens.size()>0){

 86             for (TreeItem it : childrens) {

 87                 recuseShow(it);

 88             }

 89         }

 90     }

 91     

 92     @Override

 93     public void onWindowFocusChanged(boolean hasWindowFocus) {

 94         super.onWindowFocusChanged(hasWindowFocus);

 95         if(hasWindowFocus){

 96             

 97         }

 98     }

 99     

100     private void sortItemList(List<TreeItem> items) {

101         //把items按照層級關系存放,sortedItems隻存放頂層的item

102         sortedItems=new ArrayList<TreeItem>(5);

103         for (TreeItem item : items) {

104             if(item.getParent()==null){

105                 sortedItems.add(item);

106             }else {

107                 item.getParent().getChildrens().add(item);

108             }

109         }

110         

111     }

112     

113     

114     private int viewIndex=0;

115     private int animHeight=0;

116     private void addChild(TreeItem item,boolean isRecurse){

117         if(item.getChildrens().size()>0){

118             List<TreeItem> list=item.getChildrens();

119             for (TreeItem it :    list) {

120                 View view=it.getView();

121                 if(it.isShow){

122                     continue;

123                 }

124                 viewIndex++;

125                 view.setVisibility(View.VISIBLE);

126                 it.isShow=true;

127                 if(isAnim){

128                     animHeight-=it.getViewHeight();

129                 }

130                 it.nextIsExpand=true;

131                 if(isRecurse){

132                     addChild(it,true);

133                 }

134             }

135         }

136     }

137     private int removeCount=0;

138     private synchronized void removeChild(TreeItem item,boolean isRecurse){

139         if(item.getChildrens().size()>0){

140             List<TreeItem> list=item.getChildrens();

141             for (TreeItem it :    list) {

142                 View view=it.getView();

143                 if(!it.isShow){

144                     continue;

145                 }

146 //                removeViewAt(viewIndex);

147                 

148                 TranslateAnimation ta=new TranslateAnimation(0, 0, 0, 0);

149                 ta.setFillAfter(true);

150                 ta.setDuration(1000);

151                 view.startAnimation(ta);

152 //                viewIndex++;

153                 removeCount++;

154                 it.isShow=false;

155                 view.setVisibility(View.GONE);

156                 if(isAnim){

157                     animHeight+=it.getViewHeight();

158                 }

159                 if(isRecurse){

160                     removeChild(it,true);

161                 }

162             }

163         }

164     }

165 

166     private void animAdd(){

167         TranslateAnimation ta=new TranslateAnimation(

168                 Animation.ABSOLUTE, 0, 

169                 Animation.ABSOLUTE, 0, 

170                 Animation.ABSOLUTE, animHeight, 

171                 Animation.ABSOLUTE, 0);

172         ta.setFillBefore(true);

173 //        ta.setFillAfter(false);

174         ta.setDuration(animTime);

175         

176         for (int i = viewIndex+1; i < getChildCount(); i++) {

177             View view=getChildAt(i);

178             view.startAnimation(ta);

179         }

180         animHeight=0;

181     }

182     private void animRemove(){

183         TranslateAnimation ta=new TranslateAnimation(

184                 Animation.ABSOLUTE, 0, 

185                 Animation.ABSOLUTE, 0, 

186                 Animation.ABSOLUTE, animHeight, 

187                 Animation.ABSOLUTE, 0);

188         ta.setFillAfter(false);

189         ta.setFillBefore(true);

190         ta.setDuration(animTime);

191         

192         int startAnimIndex;

193         startAnimIndex=viewIndex+1;

194         for (int i = startAnimIndex; i < getChildCount(); i++) {

195             View view=getChildAt(i);

196             

197             view.startAnimation(ta);

198         }

199         animHeight=0;

200     }

201     public void expand(TreeItem item){

202         viewIndex=indexOfChild(item.getView());

203         addChild(item,false);

204         if(isAnim){

205             animAdd();

206         }

207     }

208     

209 

210     public void expandAllChildren(TreeItem item) {

211         viewIndex=indexOfChild(item.getView());

212         addChild(item,true);

213         if(isAnim){

214             animAdd();

215         }

216     }

217     

218     public void expandAll(){

219         if(sortedItems==null){

220             return ;

221         }

222         for (TreeItem item : sortedItems) {

223             expandAllChildren(item);

224         }

225     }

226     

227     public void contractAllChildren(TreeItem item) {

228         viewIndex=indexOfChild(item.getView())+1;

229         removeChild(item,true);

230         if(isAnim){

231             animRemove();

232         }

233     }

234     

235     public void contractAll(){

236         if(sortedItems==null){

237             return ;

238         }

239         for (TreeItem item : sortedItems) {

240             contractAllChildren(item);

241         }

242     }

243     

244     public void bind(TreeItem item) {

245         if(item.nextIsExpand){

246             expand(item);

247         }else {

248             contractAllChildren(item);

249         }

250         item.nextIsExpand=!item.nextIsExpand;

251     }

252     

253     

254 }

復制代碼

TreeItem.java

 

 

復制代碼

 1 package net.memornote.android.ui.view;

 2 

 3 import java.util.ArrayList;

 4 import java.util.List;

 5 

 6 import android.view.View;

 7 

 8 public class TreeItem {

 9     private View view;

10     private TreeItem parent;

11     private List<TreeItem> childrens=new ArrayList<TreeItem>(0);

12     public boolean nextIsExpand=true;

13     public boolean isShow=false;

14     private int viewHeight;  

15     

16     

17     public TreeItem(){}

18     public TreeItem(int id,View view, TreeItem parent) {

19         super();

20         this.view = view;

21         this.parent = parent;

22     }

23 

24     public View getView() {

25         if(view!=null){

26             view.setPadding(getLevel()*20,0,0,0);

27         }

28         return view;

29     }

30 

31     public void setView(View view) {

32         this.view = view;

33     }

34 

35     public TreeItem getParent() {

36         return parent;

37     }

38 

39     public void setParent(TreeItem parent) {

40         this.parent = parent;

41     }

42 

43     /**

44      * 動態獲取該節點的級數

45      * @return

46      */

47     public int getLevel() {

48         int level=0;

49         TreeItem localParent=parent;

50         

51         while (localParent!=null) {

52             level++;

53             localParent=localParent.getParent();

54         }

55         

56         return level;

57     }

58     public List<TreeItem> getChildrens() {

59         return childrens;

60     }

61     public int getViewHeight() {

62         if(view==null||view.getHeight()==0){

63             return viewHeight;

64         }

65         return view.getHeight();

66     }

67     public void setViewHeight(int viewHeight) {

68         this.viewHeight = viewHeight;

69     }

70     

71 

72 }

復制代碼

測試代碼:

 

 

復制代碼

 1 package net.memornote.android.ui;

 2 

 3 import net.memornote.android.R;

 4 import net.memornote.android.ui.fragment.MainFragment;

 5 import net.memornote.android.ui.fragment.MenuFragment;

 6 

 7 import com.actionbarsherlock.view.Menu;

 8 import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;

 9 import com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity;

10 

11 import android.os.Bundle;

12 import android.view.KeyEvent;

13 

14 public class MainActivity extends SlidingFragmentActivity {

15 

16     

17     @Override

18     public void onCreate(Bundle savedInstanceState) {

19         super.onCreate(savedInstanceState);

20         

21         setContentView(R.layout.slid_content_frame);

22 

23                 tv_notebook=(TreeView)   findViewById(R.id.tv_notebook);

24         

25         List<TreeItem> items=new ArrayList<TreeItem>();

26         

27         initData(items);

28         tv_notebook.initData(items, 0);

29         tv_notebook.enabledAnim(500);

30         

31     }

32     //初始化一些測試數據

33     public void initData(List<TreeItem> items) {

34         for (int i=0;i<10;i++) {

35 //            TextView tv=new TextView(getActivity());

36             Button button=new Button(getActivity());

37             button.setText("item"+i);

38             final TreeItem item=new TreeItem(0, button, null);

39             

40             button.setOnClickListener(new OnClickListener() {

41                 @Override

42                 public void onClick(View v) {

43                     tv_notebook.bind(item);

44                 }

45             });

46             

47             items.add(item);

48             

49             if(i%2==0){

50                 Button bt1=new Button(getActivity());

51                 bt1.setText("item"+i);

52                 bt1.setClickable(true);

53                 final TreeItem item_1=new TreeItem(0, bt1, null);

54                 

55                 bt1.setOnClickListener(new OnClickListener() {

56                     @Override

57                     public void onClick(View v) {

58 

59                         tv_notebook.bind(item_1);

60                     }

61                 });

62                 item_1.setParent(item);

63                 items.add(item_1);

64                 

65                 if(i%4==0){

66                     Button bt_2=new Button(getActivity());

67                     bt_2.setText("item"+i);

68                     bt_2.setClickable(true);

69                     final TreeItem item_2=new TreeItem(0, bt_2, null);

70                     

71                     bt_2.setOnClickListener(new OnClickListener() {

72                         @Override

73                         public void onClick(View v) {

74                             tv_notebook.bind(item_2);

75                         }

76                     });

77                     item_2.setParent(item_1);

78                     items.add(item_2);

79                 }

80                 

81             }

82             

83             

84         }

85     }

86 

87     @Override

88     public boolean onCreateOptionsMenu(Menu menu) {

89         return true;

90     }

91 

92 }

93         

復制代碼

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *