至於該效果如何? 就是個可以展開/收起的一個listview(視覺效果不錯)
------------------------------------------------------------------------------------------
首先建立一個主要的xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.daniel.exandableListview.AnimatedExpandableListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:listSelector="@drawable/selector_list_item"
/>
</RelativeLayout>
然後:
group_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingRight="10dp"
android:paddingLeft="40dp">
<TextView
android:id="@+id/textTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
<!-- android:textColor="#FFFFFF" -->
</LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingRight="10dp"
    android:paddingLeft="50dp">
    <TextView
        android:id="@+id/textTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
         />
 <!-- android:textColor="#FFFFFF" -->
    <TextView
        android:id="@+id/textHint"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#1874CD" />
</LinearLayout>
最後要增加一個Java檔:
AnimatedExpandableListView.java
package com.daniel.exandableListview; 
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.Transformation;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
/**
 * This class defines an ExpandableListView which supports animations for
 * collapsing and expanding groups.
 */
public class AnimatedExpandableListView extends ExpandableListView {
    /*
     * A detailed explanation for how this class works:
     *
     * Animating the ExpandableListView was no easy task. The way that this
     * class does it is by exploiting how an ExpandableListView works.
     *
     * Normally when {@link ExpandableListView#collapseGroup(int)} or
     * {@link ExpandableListView#expandGroup(int)} is called, the view toggles
     * the flag for a group and calls notifyDataSetChanged to cause the ListView
     * to refresh all of it's view. This time however, depending on whether a
     * group is expanded or collapsed, certain childViews will either be ignored
     * or added to the list.
     *
     * Knowing this, we can come up with a way to animate our views. For
     * instance for group expansion, we tell the adapter to animate the
     * children of a certain group. We then expand the group which causes the
     * ExpandableListView to refresh all views on screen. The way that
     * ExpandableListView does this is by calling getView() in the adapter.
     * However since the adapter knows that we are animating a certain group,
     * instead of returning the real views for the children of the group being
     * animated, it will return a fake dummy view. This dummy view will then
     * draw the real child views within it's dispatchDraw function. The reason
     * we do this is so that we can animate all of it's children by simply
     * animating the dummy view. After we complete the animation, we tell the
     * adapter to stop animating the group and call notifyDataSetChanged. Now
     * the ExpandableListView is forced to refresh it's views again, except this
     * time, it will get the real views for the expanded group.
     *
     * So, to list it all out, when {@link #expandGroupWithAnimation(int)} is
     * called the following happens:
     *
     * 1. The ExpandableListView tells the adapter to animate a certain group.
     * 2. The ExpandableListView calls expandGroup.
     * 3. ExpandGroup calls notifyDataSetChanged.
     * 4. As an result, getChildView is called for expanding group.
     * 5. Since the adapter is in "animating mode", it will return a dummy view.
     * 6. This dummy view draws the actual children of the expanding group.
     * 7. This dummy view's height is animated from 0 to it's expanded height.
     * 8. Once the animation completes, the adapter is notified to stop
     *    animating the group and notifyDataSetChanged is called again.
     * 9. This forces the ExpandableListView to refresh all of it's views again.
     * 10.This time when getChildView is called, it will return the actual
     *    child views.
     *
     * For animating the collapse of a group is a bit more difficult since we
     * can't call collapseGroup from the start as it would just ignore the
     * child items, giving up no chance to do any sort of animation. Instead
     * what we have to do is play the animation first and call collapseGroup
     * after the animation is done.
     *
     * So, to list it all out, when {@link #collapseGroupWithAnimation(int)} is
     * called the following happens:
     *
     * 1. The ExpandableListView tells the adapter to animate a certain group.
     * 2. The ExpandableListView calls notifyDataSetChanged.
     * 3. As an result, getChildView is called for expanding group.
     * 4. Since the adapter is in "animating mode", it will return a dummy view.
     * 5. This dummy view draws the actual children of the expanding group.
     * 6. This dummy view's height is animated from it's current height to 0.
     * 7. Once the animation completes, the adapter is notified to stop
     *    animating the group and notifyDataSetChanged is called again.
     * 8. collapseGroup is finally called.
     * 9. This forces the ExpandableListView to refresh all of it's views again.
     * 10.This time when the ListView will not get any of the child views for
     *    the collapsed group.
     */
    @SuppressWarnings("unused")
 private static final String TAG = AnimatedExpandableListAdapter.class.getSimpleName();
    /**
     * The duration of the expand/collapse animations
     */
    private static final int ANIMATION_DURATION = 300;
    private AnimatedExpandableListAdapter adapter;
    public AnimatedExpandableListView(Context context) {
        super(context);
    }
    public AnimatedExpandableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public AnimatedExpandableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    /**
     * @see ExpandableListView#setAdapter(ExpandableListAdapter)
     */
    public void setAdapter(ExpandableListAdapter adapter) {
        super.setAdapter(adapter);
        // Make sure that the adapter extends AnimatedExpandableListAdapter
        if(adapter instanceof AnimatedExpandableListAdapter) {
            this.adapter = (AnimatedExpandableListAdapter) adapter;
            this.adapter.setParent(this);
        } else {
            throw new ClassCastException(adapter.toString() + " must implement AnimatedExpandableListAdapter");
        }
    }
    /**
     * Expands the given group with an animation.
     * @param groupPos The position of the group to expand
     * @return  Returns true if the group was expanded. False if the group was
     *          already expanded.
     */
    @SuppressLint("NewApi") 
    public boolean expandGroupWithAnimation(int groupPos) {
     boolean lastGroup = groupPos == adapter.getGroupCount() - 1;
     if (lastGroup && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      return expandGroup(groupPos, true);
     }
        int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));
        if (groupFlatPos != -1) {
            int childIndex = groupFlatPos - getFirstVisiblePosition();
            if (childIndex < getChildCount()) {
                // Get the view for the group is it is on screen...
                View v = getChildAt(childIndex);
                if (v.getBottom() >= getBottom()) {
                    // If the user is not going to be able to see the animation
                    // we just expand the group without an animation.
                    // This resolves the case where getChildView will not be
                    // called if the children of the group is not on screen
                    // We need to notify the adapter that the group was expanded
                    // without it's knowledge
                    adapter.notifyGroupExpanded(groupPos);
                    return expandGroup(groupPos);
                }
            }
        }
        // Let the adapter know that we are starting the animation...
        adapter.startExpandAnimation(groupPos, 0);
        // Finally call expandGroup (note that expandGroup will call
        // notifyDataSetChanged so we don't need to)
        return expandGroup(groupPos);
    }
    /**
     * Collapses the given group with an animation.
     * @param groupPos The position of the group to collapse
     * @return  Returns true if the group was collapsed. False if the group was
     *          already collapsed.
     */
    public boolean collapseGroupWithAnimation(int groupPos) {
        int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));
        if (groupFlatPos != -1) {
            int childIndex = groupFlatPos - getFirstVisiblePosition();
            if (childIndex >= 0 && childIndex < getChildCount()) {
                // Get the view for the group is it is on screen...
                View v = getChildAt(childIndex);
                if (v.getBottom() >= getBottom()) {
                    // If the user is not going to be able to see the animation
                    // we just collapse the group without an animation.
                    // This resolves the case where getChildView will not be
                    // called if the children of the group is not on screen
                    return collapseGroup(groupPos);
                }
            } else {
                // If the group is offscreen, we can just collapse it without an
                // animation...
                return collapseGroup(groupPos);
            }
        }
        // Get the position of the firstChild visible from the top of the screen
        long packedPos = getExpandableListPosition(getFirstVisiblePosition());
        int firstChildPos = getPackedPositionChild(packedPos);
        int firstGroupPos = getPackedPositionGroup(packedPos);
        // If the first visible view on the screen is a child view AND it's a
        // child of the group we are trying to collapse, then set that
        // as the first child position of the group... see
        // {@link #startCollapseAnimation(int, int)} for why this is necessary
        firstChildPos = firstChildPos == -1 || firstGroupPos != groupPos ? 0 : firstChildPos;
        // Let the adapter know that we are going to start animating the
        // collapse animation.
        adapter.startCollapseAnimation(groupPos, firstChildPos);
        // Force the listview to refresh it's views
        adapter.notifyDataSetChanged();
        return isGroupExpanded(groupPos);
    }
    private int getAnimationDuration() {
        return ANIMATION_DURATION;
    }
    /**
     * Used for holding information regarding the group.
     */
    private static class GroupInfo {
        boolean animating = false;
        boolean expanding = false;
        int firstChildPosition;
        /**
         * This variable contains the last known height value of the dummy view.
         * We save this information so that if the user collapses a group
         * before it fully expands, the collapse animation will start from the
         * CURRENT height of the dummy view and not from the full expanded
         * height.
         */
        int dummyHeight = -1;
    }
    /**
     * A specialized adapter for use with the AnimatedExpandableListView. All
     * adapters used with AnimatedExpandableListView MUST extend this class.
     */
    public static abstract class AnimatedExpandableListAdapter extends BaseExpandableListAdapter {
        private SparseArray<GroupInfo> groupInfo = new SparseArray<GroupInfo>();
        private AnimatedExpandableListView parent;
        private static final int STATE_IDLE = 0;
        private static final int STATE_EXPANDING = 1;
        private static final int STATE_COLLAPSING = 2;
        private void setParent(AnimatedExpandableListView parent) {
            this.parent = parent;
        }
        public int getRealChildType(int groupPosition, int childPosition) {
            return 0;
        }
        public int getRealChildTypeCount() {
            return 1;
        }
        public abstract View getRealChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent);
        public abstract int getRealChildrenCount(int groupPosition);
        private GroupInfo getGroupInfo(int groupPosition) {
            GroupInfo info = groupInfo.get(groupPosition);
            if (info == null) {
                info = new GroupInfo();
                groupInfo.put(groupPosition, info);
            }
            return info;
        }
        public void notifyGroupExpanded(int groupPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            info.dummyHeight = -1;
        }
        private void startExpandAnimation(int groupPosition, int firstChildPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            info.animating = true;
            info.firstChildPosition = firstChildPosition;
            info.expanding = true;
        }
        private void startCollapseAnimation(int groupPosition, int firstChildPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            info.animating = true;
            info.firstChildPosition = firstChildPosition;
            info.expanding = false;
        }
        private void stopAnimation(int groupPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            info.animating = false;
        }
        /**
         * Override {@link #getRealChildType(int, int)} instead.
         */
        @Override
        public final int getChildType(int groupPosition, int childPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            if (info.animating) {
                // If we are animating this group, then all of it's children
                // are going to be dummy views which we will say is type 0.
                return 0;
            } else {
                // If we are not animating this group, then we will add 1 to
                // the type it has so that no type id conflicts will occur
                // unless getRealChildType() returns MAX_INT
                return getRealChildType(groupPosition, childPosition) + 1;
            }
        }
        /**
         * Override {@link #getRealChildTypeCount()} instead.
         */
        @Override
        public final int getChildTypeCount() {
            // Return 1 more than the childTypeCount to account for DummyView
            return getRealChildTypeCount() + 1;
        }
        protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
            return new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                ViewGroup.LayoutParams.WRAP_CONTENT, 0);
        }
        /**
         * Override {@link #getChildView(int, int, boolean, View, ViewGroup)} instead.
         */
        @Override
        public final View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
            final GroupInfo info = getGroupInfo(groupPosition);
            if (info.animating) {
                // If this group is animating, return the a DummyView...
                if (convertView instanceof DummyView == false) {
                    convertView = new DummyView(parent.getContext());
                    convertView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, 0));
                }
                if (childPosition < info.firstChildPosition) {
                    // The reason why we do this is to support the collapse
                    // this group when the group view is not visible but the
                    // children of this group are. When notifyDataSetChanged
                    // is called, the ExpandableListView tries to keep the
                    // list position the same by saving the first visible item
                    // and jumping back to that item after the views have been
                    // refreshed. Now the problem is, if a group has 2 items
                    // and the first visible item is the 2nd child of the group
                    // and this group is collapsed, then the dummy view will be
                    // used for the group. But now the group only has 1 item
                    // which is the dummy view, thus when the ListView is trying
                    // to restore the scroll position, it will try to jump to
                    // the second item of the group. But this group no longer
                    // has a second item, so it is forced to jump to the next
                    // group. This will cause a very ugly visual glitch. So
                    // the way that we counteract this is by creating as many
                    // dummy views as we need to maintain the scroll position
                    // of the ListView after notifyDataSetChanged has been
                    // called.
                    convertView.getLayoutParams().height = 0;
                    return convertView;
                }
                final ExpandableListView listView = (ExpandableListView) parent;
                final DummyView dummyView = (DummyView) convertView;
                // Clear the views that the dummy view draws.
                dummyView.clearViews();
                // Set the style of the divider
                dummyView.setDivider(listView.getDivider(), parent.getMeasuredWidth(), listView.getDividerHeight());
                // Make measure specs to measure child views
                final int measureSpecW = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY);
                final int measureSpecH = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                int totalHeight = 0;
                int clipHeight = parent.getHeight();
                final int len = getRealChildrenCount(groupPosition);
                for (int i = info.firstChildPosition; i < len; i++) {
                    View childView = getRealChildView(groupPosition, i, (i == len - 1), null, parent);
                    LayoutParams p = (LayoutParams) childView.getLayoutParams();
                    if (p == null) {
                        p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
                        childView.setLayoutParams(p);
                    }
                    int lpHeight = p.height;
                    int childHeightSpec;
                    if (lpHeight > 0) {
                        childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
                    } else {
                        childHeightSpec = measureSpecH;
                    }
                    childView.measure(measureSpecW, childHeightSpec);
                    totalHeight += childView.getMeasuredHeight();
                    if (totalHeight < clipHeight) {
                        // we only need to draw enough views to fool the user...
                        dummyView.addFakeView(childView);
                    } else {
                        dummyView.addFakeView(childView);
                        // if this group has too many views, we don't want to
                        // calculate the height of everything... just do a light
                        // approximation and break
                        int averageHeight = totalHeight / (i + 1);
                        totalHeight += (len - i - 1) * averageHeight;
                        break;
                    }
                }
                Object o;
                int state = (o = dummyView.getTag()) == null ? STATE_IDLE : (Integer) o;
                if (info.expanding && state != STATE_EXPANDING) {
                    ExpandAnimation ani = new ExpandAnimation(dummyView, 0, totalHeight, info);
                    ani.setDuration(this.parent.getAnimationDuration());
                    ani.setAnimationListener(new AnimationListener() {
                        @Override
                        public void onAnimationEnd(Animation animation) {
                            stopAnimation(groupPosition);
                            notifyDataSetChanged();
                            dummyView.setTag(STATE_IDLE);
                        }
                        @Override
                        public void onAnimationRepeat(Animation animation) {}
                        @Override
                        public void onAnimationStart(Animation animation) {}
                    });
                    dummyView.startAnimation(ani);
                    dummyView.setTag(STATE_EXPANDING);
                } else if (!info.expanding && state != STATE_COLLAPSING) {
                    if (info.dummyHeight == -1) {
                        info.dummyHeight = totalHeight;
                    }
                    ExpandAnimation ani = new ExpandAnimation(dummyView, info.dummyHeight, 0, info);
                    ani.setDuration(this.parent.getAnimationDuration());
                    ani.setAnimationListener(new AnimationListener() {
                        @Override
                        public void onAnimationEnd(Animation animation) {
                            stopAnimation(groupPosition);
                            listView.collapseGroup(groupPosition);
                            notifyDataSetChanged();
                            info.dummyHeight = -1;
                            dummyView.setTag(STATE_IDLE);
                        }
                        @Override
                        public void onAnimationRepeat(Animation animation) {}
                        @Override
                        public void onAnimationStart(Animation animation) {}
                    });
                    dummyView.startAnimation(ani);
                    dummyView.setTag(STATE_COLLAPSING);
                }
                return convertView;
            } else {
                return getRealChildView(groupPosition, childPosition, isLastChild, convertView, parent);
            }
        }
        @Override
        public final int getChildrenCount(int groupPosition) {
            GroupInfo info = getGroupInfo(groupPosition);
            if (info.animating) {
                return info.firstChildPosition + 1;
            } else {
                return getRealChildrenCount(groupPosition);
            }
        }
    }
    private static class DummyView extends View {
        private List<View> views = new ArrayList<View>();
        private Drawable divider;
        private int dividerWidth;
        private int dividerHeight;
        public DummyView(Context context) {
            super(context);
        }
        public void setDivider(Drawable divider, int dividerWidth, int dividerHeight) {
         if(divider != null) {
          this.divider = divider;
          this.dividerWidth = dividerWidth;
          this.dividerHeight = dividerHeight;
          divider.setBounds(0, 0, dividerWidth, dividerHeight);
         }
        }
        /**
         * Add a view for the DummyView to draw.
         * @param childView View to draw
         */
        public void addFakeView(View childView) {
            childView.layout(0, 0, getWidth(), childView.getMeasuredHeight());
            views.add(childView);
        }
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            final int len = views.size();
            for(int i = 0; i < len; i++) {
                View v = views.get(i);
                v.layout(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
            }
        }
        public void clearViews() {
            views.clear();
        }
        @Override
        public void dispatchDraw(Canvas canvas) {
            canvas.save();
            if(divider != null) {
                divider.setBounds(0, 0, dividerWidth, dividerHeight);
            }
            final int len = views.size();
            for(int i = 0; i < len; i++) {
                View v = views.get(i);
                canvas.save();
                canvas.clipRect(0, 0, getWidth(), v.getMeasuredHeight());
                v.draw(canvas);
                canvas.restore();
                if(divider != null) {
                    divider.draw(canvas);
                    canvas.translate(0, dividerHeight);
                }
                canvas.translate(0, v.getMeasuredHeight());
            }
            canvas.restore();
        }
    }
    private static class ExpandAnimation extends Animation {
        private int baseHeight;
        private int delta;
        private View view;
        private GroupInfo groupInfo;
        private ExpandAnimation(View v, int startHeight, int endHeight, GroupInfo info) {
            baseHeight = startHeight;
            delta = endHeight - startHeight;
            view = v;
            groupInfo = info;
            view.getLayoutParams().height = startHeight;
            view.requestLayout();
        }
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                int val = baseHeight + (int) (delta * interpolatedTime);
                view.getLayoutParams().height = val;
                groupInfo.dummyHeight = val;
                view.requestLayout();
            } else {
                int val = baseHeight + delta;
                view.getLayoutParams().height = val;
                groupInfo.dummyHeight = val;
                view.requestLayout();
            }
        }
    }
}
---------------------------------------------------------------------------------------------------------------------
準備工作都完成以後,我們就可以來使用這個expandable listview,但是很顯然還不知道該如何使
用,所以現在就來教學囉!
這邊是用一個分頁(fragment)來做個listview,所以寫在oncreateview()裡面,
首先是標題:
標題使用String[] Title_big 來建立標題集合
中標與小標(或註解)則是使用ChildItem 來建立(這裡是用switch case來判別每一個中標/註解放
甚麼東西)
有了大標題/中標題+註解之後,接下來的問題就是如何點選以後觸發事件??
 listView.setOnChildClickListener(new OnChildClickListener(){
   public boolean onChildClick(ExpandableListView parent, View v,
     int groupPosition, int childPosition, long id) {
    int index = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
       parent.setItemChecked(index, true);
    switch (groupPosition) {
這一段就是讓你的中標題能觸發事件,我們用switch...case來取得groupPosition
然後再去裡面細分childPosition,最後才在裡面寫觸發事件!
package com.Daniel_pcm.android;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupClickListener;
import android.widget.TextView;
import com.daniel.exandableListview.AnimatedExpandableListView;
public class Setting extends Fragment{
 private AnimatedExpandableListView listView;
    private ExampleAdapter adapter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  View v = LayoutInflater.from(getActivity()).inflate(R.layout.tab3_setting,null);
        List<GroupItem> items = new ArrayList<GroupItem>();
        String[] Title_big = new String[]{MainActivity.Language_content[65],MainActivity.Language_content[63],MainActivity.Language_content[77]};
        //標題
         // Populate our list with groups and it's children
         for(int i = 0; i < Title_big.length; i++) { //總數
         GroupItem item = new GroupItem();    
         item.title = Title_big[i]; //大標題名稱
         if (i == 0) {
    for (int j = 0; j < 2; j++) {
     ChildItem child = new ChildItem();
     if(j == 0)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";//這邊可以改為直接顯示在這
     }
     if(j == 1)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";
     }
     item.items.add(child);
    }
   }         
   if (i == 1) {
//    ChildItem child = new ChildItem();
//    child.title = "多國語言";
//    child.hint = "選擇其他語言";
//    item.items.add(child);
    for (int j = 0; j < 7; j++) {
     ChildItem child = new ChildItem();
     if(j == 0)
     {
      child.title = "中文"; // 中標題名稱 + 編號
      child.hint = "Chinese";
     }
     if(j == 1)
     {
      child.title = "English"; // 中標題名稱 + 編號
      child.hint = "English";
     }
     if(j == 2)
     {
      child.title = "русский язык"; // 中標題名稱 + 編號
      child.hint = "Russian";
     }
     if(j == 3)
     {
      child.title = "اللغة العربية"; // 中標題名稱 + 編號
      child.hint = "Arabian";
     }
     if(j == 4)
     {
      child.title = "español"; // 中標題名稱 + 編號
      child.hint = "Spainish";
     }
     if(j == 5)
     {
      child.title = "Italiano"; // 中標題名稱 + 編號
      child.hint = "Italish";
     }
     if(j == 6)
     {
      child.title = "Deutsch"; // 中標題名稱 + 編號
      child.hint = "Deutsch";
     }    
     item.items.add(child);
    }    
   }
   if (i == 2) {
    for (int j = 0; j < 4; j++) {
     ChildItem child = new ChildItem();
     if(j == 0)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";
     }
     if(j == 1)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";
     }
     if(j == 2)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";
     }
     if(j == 3)
     {
      child.title = ""; // 中標題名稱 + 編號
      child.hint = "";
     }     
     item.items.add(child);
    }
   }
             items.add(item);
         }
         Context mContext = getActivity();
         adapter = new ExampleAdapter(mContext);
         adapter.setData(items);
         listView = (AnimatedExpandableListView) v.findViewById(R.id.listView);
         listView.setAdapter(adapter);
         listView.setOnChildClickListener(new OnChildClickListener(){
   public boolean onChildClick(ExpandableListView parent, View v,
     int groupPosition, int childPosition, long id) {
    int index = parent.getFlatListPosition(ExpandableListView.getPackedPositionForChild(groupPosition, childPosition));
       parent.setItemChecked(index, true);
    switch (groupPosition) {
    case 0: //第一組(連線)
     switch (childPosition) {
     case 0://第一個選項-目前IP
      Log.d("one","connect child!");
      MainActivity.handler_main.sendMessage(MainActivity.handler_main.obtainMessage(6));
      break;
     case 1://第二個選項-連線
      //popup_ip
      MainActivity.handler_main.sendMessage(MainActivity.handler_main.obtainMessage(3));
      break;
     }
     break;
    case 1://第二組(語言)
     System.out.print("Language change in!");
     int language_serial = 0;
     switch (childPosition) {
     case 0://第一選項(選語言)
      language_serial = 0;
      break;
     case 1:
      language_serial = 1;
      break;
     case 2:
      language_serial = 2;
      break;
     case 3:
      language_serial = 3;
      break;
     case 4:
      language_serial = 4;
      break;
     case 5:
      language_serial = 5;
      break;
     case 6:
      language_serial = 6;
      break;     
     }  
     MainActivity.handler_main.sendMessage(MainActivity.handler_main.obtainMessage(4,language_serial));
     System.out.print("Language change success!");
     break;
    case 2://第三組(控制)
     switch (childPosition) {
     case 0://第一選項(outlet control)
      MainActivity.handler_main.sendMessage(MainActivity.handler_main.obtainMessage(5));      
      break;
     case 1://第二選項(UPS quick test)
      if (Static_Var.PRO_now == true) {
       // 如果現在是PRO
       Static_Var.PRO_Self_test = true;
       Log.d("PRO Self test flag","on");
      }
      if (Static_Var.SNMP_now == true) {
       // 如果現在是SNMP
       Static_Var.SNMP_Self_test = true;
       Log.d("SNMP Self test flag","on");
      }      
      break;
     case 2://第三選項(UPS Deep test)
      break;
     case 3://第四選項(取消test)
      break;
     }     
     break;     
    }
    return false;
   }
         });
         // In order to show animations, we need to use a custom click handler
         // for our ExpandableListView.
         listView.setOnGroupClickListener(new OnGroupClickListener() {
             @Override
             public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                 // We call collapseGroupWithAnimation(int) and
                 // expandGroupWithAnimation(int) to animate group 
                 // expansion/collapse.
                 if (listView.isGroupExpanded(groupPosition)) {
                     listView.collapseGroupWithAnimation(groupPosition);
                     //Log.d("Position",Integer.toString(groupPosition));//GroupPosition 是最大標題
                 } else {
                     listView.expandGroupWithAnimation(groupPosition);
                 }
                 return true;
             }
         });
  return v;
 }
    private static class GroupItem {
        String title;
        List<ChildItem> items = new ArrayList<ChildItem>();
    }
    private static class ChildItem {
        String title;
        String hint;
    }
    private static class ChildHolder {
        TextView title;
        TextView hint;
    }
    private static class GroupHolder {
        TextView title;
    }  
    /**
     * Adapter for our list of {@link GroupItem}s.
     */
    private class ExampleAdapter extends com.daniel.exandableListview.AnimatedExpandableListView.AnimatedExpandableListAdapter {
        private LayoutInflater inflater;
        private List<GroupItem> items;
        public ExampleAdapter(Context context) {
             inflater = LayoutInflater.from(context);
        }
        public void setData(List<GroupItem> items) {
            this.items = items;
        }
        @Override
        public ChildItem getChild(int groupPosition, int childPosition) {
            return items.get(groupPosition).items.get(childPosition);
        }
        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }
        @Override
        public View getRealChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
            ChildHolder holder;
            ChildItem item = getChild(groupPosition, childPosition);
            if (convertView == null) {
                holder = new ChildHolder();
                convertView = inflater.inflate(R.layout.list_item, parent, false);
                holder.title = (TextView) convertView.findViewById(R.id.textTitle);
                holder.hint = (TextView) convertView.findViewById(R.id.textHint);
                convertView.setTag(holder);
            } else {
                holder = (ChildHolder) convertView.getTag();
            }
            holder.title.setText(item.title);
            holder.hint.setText(item.hint);
            return convertView;
        }
        @Override
        public int getRealChildrenCount(int groupPosition) {
            return items.get(groupPosition).items.size();
        }
        @Override
        public GroupItem getGroup(int groupPosition) {
            return items.get(groupPosition);
        }
        @Override
        public int getGroupCount() {
            return items.size();
        }
        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }
        @Override
        public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
            GroupHolder holder;
            GroupItem item = getGroup(groupPosition);
            if (convertView == null) {
                holder = new GroupHolder();
                convertView = inflater.inflate(R.layout.group_item, parent, false);
                holder.title = (TextView) convertView.findViewById(R.id.textTitle);
                convertView.setTag(holder);
            } else {
                holder = (GroupHolder) convertView.getTag();
            }
            holder.title.setText(item.title);          
            return convertView;
        }
        @Override
        public boolean hasStableIds() {
            return true;
        }
        @Override
        public boolean isChildSelectable(int arg0, int arg1) {
            return true;
        }
    }
}
整個Expandable listview教學就到這裡!
基本上,稍作修改應該就可以變成自己的東西囉!
基本上,稍作修改應該就可以變成自己的東西囉!
END
