1.开发原因
在项目中经常需要一个需要一个树状框架,这是非常常见的控件。不过可能是谷歌考虑到android是手机系统,界面宽度有限,所以只提供了只有二级的ExpandableListView。虽然这个控件可以满足很多需求,但是无数级的树在某些情况下还是需要的,所以我花了一天时间(大部分时间都在调试动画去了,不过现在动画还有点问题,具体原因不明。。如果某位大神能找到原因灰常感谢)。
2.原理
网上很多都是扩展listview实现的,不过listview貌似不支持复杂控件的事件?而且做动画也不方便,所有我决定扩展linearlayout,在里面增加子节点的方式实现。
3.代码
TreeView.java:
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;
}
}
本文地址:https://www.stayed.cn/item/14198
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我