天天看点

UI组件之AdapterView及其子类(六)ExpandableListView组件和ExpandableListActivity的使用

ExpandableListView是ListView的子类,他在ListView上进行了扩展,它把列表项分成了几组,每组里包含了多个列表项

ExpandableListView的列表项是由ExpandableListAdapter提供的,实现ExpandableListAdapter三种常用方式,常用的ExpandableListAdapter子类如下:

1,扩展BaseExpandableListAdapter实现ExpandableListAdapter

2,使用SimpleExpandableListAdapter将 两个List集合包装成ExpandableListAdapter

3,使用SimpleCursorTreeAdapter将Cursor中的数据包装成SimpleCursorTreeAdapter

ExpandableListAdapter及其子类的继承关系类图看这篇文章讲的比较好,看懂了:http://hubingforever.blog.163.com/blog/static/1710405792010538823477/

ExpandableListView的xml属性:

UI组件之AdapterView及其子类(六)ExpandableListView组件和ExpandableListActivity的使用

     android:childDivider 指定个组内各子列表项之间的分隔条

     android:childIndicator 显示子列表项旁边的Drawble对象

     android:groupIndicator 显示组列表项旁边的Drawble对象

ExpandableListView是android中可以实现下拉list的一个控件,是一个垂直滚动的心事两个级别列表项手风琴试图,列表项是来自ExpandableListViewaAdapter,组可以单独展开。

重要方法:

<span style="font-size:24px;">expandGroup (int groupPos) ;//在分组列表视图中 展开一组,
setSelectedGroup (int groupPosition) ;//设置选择指定的组。
setSelectedChild (int groupPosition, int childPosition, boolean shouldExpandGroup);//设置选择指定的子项。
getPackedPositionGroup (long packedPosition);//返回所选择的组 
getPackedPositionForChild (int groupPosition, int childPosition) ;//返回所选择的子项 
getPackedPositionType (long packedPosition);//返回所选择项的类型(Child,Group)
isGroupExpanded (int groupPosition);//判断此组是否展开</span>           
<span style="font-size:24px;">expandableListView.setDivider();这个是设定每个Group之间的分割线。
expandableListView.setGroupIndicator();这个是设定每个Group之前的那个图标。
expandableListView.collapseGroup(int group); 将第group组收起</span>           

一,使用扩展BaseExpandableListAdapter来提供数据源

扩展BaseExpandableListAdapter需要重写11个方法:

      * getGroupCount(),返回包含组列表的数量

             * getChildrenCount(int groupPosition),返回包含组列表的数量

             * 

             * getGroup(int groupPosition),返回组列表的对象

             * getChild(int groupPosition, int childPosition),返回组列表下的子列表对象

             * 

             * getGroupId(int groupPosition),返回组列表Id

             * getChildId(int groupPosition, int childPosition),返回祖列表的子列表的Id

             * 下面两个属性很重要!

             * getGroupView(int groupPosition, boolean isExpanded,

View convertView, ViewGroup parent),该方法决定每个组选项的外观、

             * getChildView(int groupPosition, int childPosition,

boolean isLastChild, View convertView, ViewGroup parent),该方法决定每个子选项的外观、

             *isChildSelectable(int groupPosition,

int childPosition):如果child添加监听事件,则要返回true

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
  <!--ExpandableListView组件
     android:childDivider 指定个组内各子列表项之间的分隔条
     android:childIndicator 显示子列表项旁边的Drawble对象
     android:groupIndicator 显示组列表项旁边的Drawble对象
  
    -->

    <ExpandableListView
        android:id="@+id/expandableListView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:childDivider="#f0f"
       >

    </ExpandableListView>

</LinearLayout>
           

MainActivity.java

package com.hust.expandablelistview;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.LayoutParams;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BaseExpandableListAdapter bela=new BaseExpandableListAdapter(){                	
            /*自动实现这10个方法
             * getGroupCount(),返回包含组列表的数量
             * getChildrenCount(int groupPosition),返回包含组列表的数量
             * 
             * getGroup(int groupPosition),返回组列表的对象
             * getChild(int groupPosition, int childPosition),返回组列表下的子列表对象
             * 
             * getGroupId(int groupPosition),返回组列表Id
             * getChildId(int groupPosition, int childPosition),返回祖列表的子列表的Id
             * 
             * getGroupView(int groupPosition, boolean isExpanded,
					View convertView, ViewGroup parent),该方法决定每个组选项的外观、
             * getChildView(int groupPosition, int childPosition,
					boolean isLastChild, View convertView, ViewGroup parent),该方法决定每个子选项的外观、
             * 
             * 
             * */
        	int[] logos=new int[]{
        			R.drawable.p,R.drawable.z,R.drawable.t
        	};
        	//组列表的数量
        	private String[] armTypes=new String[]{"我的好友","高中同学","大学同学"};
        	//组列表下的子列表项,可扩展的ExpandableListView是个二维数组
        	private String[][] arms=new String[][]{
        			{"狂战士","龙骑士","黑暗圣堂","电兵"},
        			{"张娜","李四","赵龙","钱爽"},
        			{"王燕","刘涛","张坦克","汪明城"}
        	};
        	//返回包含组列表的数量
			@Override
			public int getGroupCount() {
				// TODO Auto-generated method stub
				return armTypes.length;
			}
           //返回组位置下的子列表项的数量
			@Override
			public int getChildrenCount(int groupPosition) {
				// TODO Auto-generated method stub
				return arms[groupPosition].length;
			}
           //返回组列表的对象
			@Override
			public Object getGroup(int groupPosition) {
				// TODO Auto-generated method stub
				return armTypes[groupPosition];
			}
           //返回组列表下的子列表对象
			@Override
			public Object getChild(int groupPosition, int childPosition) {
				// TODO Auto-generated method stub
				return arms[groupPosition][childPosition];
			}
            //返回组列表Id
			@Override
			public long getGroupId(int groupPosition) {
				// TODO Auto-generated method stub
				return groupPosition;
			}
            //返回祖列表的子列表的Id
			@Override
			public long getChildId(int groupPosition, int childPosition) {
				// TODO Auto-generated method stub
				return childPosition;
			}

			@Override
			public boolean hasStableIds() {
				// TODO Auto-generated method stub
				return true;
			}
            //该方法决定每个组选项的外观、这里这定义组列表布局,也可以用xml文件
			@Override
			public View getGroupView(int groupPosition, boolean isExpanded,
					View convertView, ViewGroup parent) {
				// TODO Auto-generated method stub
				 LinearLayout ll=new LinearLayout(MainActivity.this);
				 ll.setOrientation(0);
				 
				 ImageView logo=new ImageView(MainActivity.this);
				 logo.setImageResource(logos[groupPosition]);
				 
				 TextView textview=getTextView();
				 textview.setText(getGroup(groupPosition).toString());
				 
				 ll.addView(logo);
				 ll.addView(textview);
				 return ll;				
			}
			//设置TextView的参数
			private TextView getTextView() {
				// TODO Auto-generated method stub
				 AbsListView.LayoutParams lp=new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,64);
				 
				 TextView textview=new TextView(MainActivity.this);
				 textview.setLayoutParams(lp);//设置布局参数,android:layout_Width="match_parent",android:layout_Height="64"
				 textview.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);//android:gravity="CENTER_VERTICAL|LEFT"
				 textview.setPadding(36, 0, 0, 0);
				 textview.setTextSize(16);	//android:textsize="20dp"			
				return textview;
			}
			//该方法决定每个子选项的外观
			@Override
			public View getChildView(int groupPosition, int childPosition,
					boolean isLastChild, View convertView, ViewGroup parent) {
				// TODO Auto-generated method stub
				TextView text=getTextView();
				text.setText(getChild(groupPosition,childPosition).toString());				
				return text;
			}

			@Override
			public boolean isChildSelectable(int groupPosition,
					int childPosition) {
				// TODO Auto-generated method stub
				return true;
			}
        	
        };
        
        ExpandableListView expandablelistview=(ExpandableListView) findViewById(R.id.expandableListView1);
       //设置adapter
        expandablelistview.setAdapter(bela);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
           
UI组件之AdapterView及其子类(六)ExpandableListView组件和ExpandableListActivity的使用

二,使用SimpleExpandableListAdapter显示ExpandableListView

SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(   
                this, gruops, R.drawable.expandablelistview_groups, new String[]{"group"}, new int[]{R.id.textGroup},    
                childs, R.drawable.expandablelistview_child, new String[]{"child"}, new int[]{R.id.textChild}   
                );            

* 参数1.上下文对象Context

* 参数2.一级条目目录集合

* 参数3.一级条目对应的布局文件 (expandablelistview_groups.xml文件

* 参数4.fromto,就是map中的key,指定要显示的对象

* 参数5.与参数4对应,指定要显示在groups中的id

* 参数6.二级条目目录集合

* 参数7.二级条目对应的布局文件

* 参数9.与参数8对应,指定要显示在childs中的id

1,定义一个主界面expandablelistview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
     <ExpandableListView 
        android:id ="@+id/expandableListView"  
        android:layout_width ="fill_parent"  
        android:layout_height ="wrap_content"  
        >
     </ExpandableListView>
</LinearLayout>           

2.在res/drawable目录下创建样式文件expandablelistview_groups.xml该界面是组界面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
     <TextView
        android:id="@+id/textGroup"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:paddingLeft="40px"  
        android:paddingTop="6px"  
        android:paddingBottom="6px"  
        android:textSize="15sp"  
        android:text="No data"  
    >   
    </TextView>
</LinearLayout>           

3.在res/drawable目录下创建样式文件expandablelistview_child.xml;是子控件,直接显示列表内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
     <TextView    
        android:id="@+id/textChild"  
        android:layout_width="fill_parent"   
        android:layout_height="fill_parent"   
        android:paddingLeft="60px"  
        android:paddingTop="10px"  
        android:paddingBottom="10px"  
        android:textSize="20sp"  
        android:text="No Data" />  
</LinearLayout>           

ExpandableListViewDemo_two.java

public class ExpandableListViewDemo_two extends Activity {
    /** Called when the activity is first created. */  
    private  ExpandableListView  expandableListView_one;
    @Override  
    public void onCreate(Bundle savedInstanceState)   
    {   
        super.onCreate(savedInstanceState);   
        setContentView(R.layout.expandablelistview);   
        expandableListView_one =(ExpandableListView)findViewById(R.id.expandableListView);   
        //创建二个一级条目标题    
        Map<String, String> title_1 = new HashMap<String, String>();   
        Map<String, String> title_2 = new HashMap<String, String>();   
            
        title_1.put("group", "移动开发");   
        title_2.put("group", "Web开发");   
            
        //创建一级条目容器    
        List<Map<String, String>> gruops = new ArrayList<Map<String,String>>();   
            
        gruops.add(title_1);   
        gruops.add(title_2);   
            
        //创建二级条目内容    
            
        //内容一    
        Map<String, String> content_1 = new HashMap<String, String>();   
        Map<String, String> content_2 = new HashMap<String, String>();   
            
        content_1.put("child", "ANDROID");   
        content_2.put("child", "IOS");   
            
        List<Map<String, String>> childs_1 = new ArrayList<Map<String,String>>();   
        childs_1.add(content_1);   
        childs_1.add(content_2);   
            
        //内容二    
        Map<String, String> content_3 = new HashMap<String, String>();   
        Map<String, String> content_4 = new HashMap<String, String>();  
        Map<String, String> content_5 = new HashMap<String, String>(); 
            
        content_3.put("child", "jsp");   
        content_4.put("child", "servlet");   
        content_5.put("child", "page"); 
        List<Map<String, String>> childs_2 = new ArrayList<Map<String,String>>();   
        childs_2.add(content_3);   
        childs_2.add(content_4);  
        childs_2.add(content_5); 
            
        //存放两个内容, 以便显示在列表中    
        List<List<Map<String, String>>> childs = new ArrayList<List<Map<String,String>>>();   
        childs.add(childs_1);   
        childs.add(childs_2);   
            
        //创建ExpandableList的Adapter容器    
/**  
* 使用SimpleExpandableListAdapter显示ExpandableListView  
* 参数1.上下文对象Context  
* 参数2.一级条目目录集合  
* 参数3.一级条目对应的布局文件 (expandablelistview_groups.xml文件 
* 参数4.fromto,就是map中的key,指定要显示的对象  
* 参数5.与参数4对应,指定要显示在groups中的id  
* 参数6.二级条目目录集合  
* 参数7.二级条目对应的布局文件  
* 参数9.与参数8对应,指定要显示在childs中的id  
/           SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(   
                this, gruops, R.drawable.expandablelistview_groups, new String[]{"group"}, new int[]{R.id.textGroup},    
                childs, R.drawable.expandablelistview_child, new String[]{"child"}, new int[]{R.id.textChild}   
                );   
            
        //加入列表    
        expandableListView_one.setAdapter(adapter); 
     expandableListView_one.setOnChildClickListener(listener);
    }   
    private OnChildClickListener  listener =new OnChildClickListener() {
   @Override
  public boolean onChildClick(ExpandableListView parent, View v,
    int groupPosition, int childPosition, long id) {
   // TODO Auto-generated method stub
   toast("点击了");
   return false;
  }
 };
 private void toast(String str) {
 Toast.makeText(this, str, Toast.LENGTH_LONG).show(); 
 } 
}           

上面的样式也可以使用系统的自带的样式如下:

android.R.layout.simple_expandable_list_item_1,//层显示样式 ,系统自定义

android.R.layout.simple_expandable_list_item_2,

ExpandableListActivity直接继承了Activity。

1,继承ExpandableListActivity

2,定义好内容ExpandableListAdapter,扩展BaseExpandableListAdapter和SimpleExpandableListAdapter都可以

3,setListAdapter的方法添加adapter 

package com.example.expandablelistactivity;

import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends ExpandableListActivity//继承ExpandableListActivity
{
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		//无需布局文件
		//自定义扩展BaseExpandableListAdapter
		ExpandableListAdapter adapter = new BaseExpandableListAdapter()
		{
			int[] logos = new int[]
			{
				R.drawable.p,
				R.drawable.z,
				R.drawable.t
			};
			//组列表的数量
        	private String[] armTypes=new String[]{"我的好友","高中同学","大学同学"};
        	//组列表下的子列表项,可扩展的ExpandableListView是个二维数组
        	private String[][] arms=new String[][]{
        			{"狂战士","龙骑士","黑暗圣堂","电兵"},
        			{"张娜","李四","赵龙","钱爽"},
        			{"王燕","刘涛","张坦克","汪明城"}
        	};
			//获取指定组位置、指定子列表项处的子列表项数据
			@Override
			public Object getChild(int groupPosition, int childPosition)
			{
				return arms[groupPosition][childPosition];
			}
			@Override
			public long getChildId(int groupPosition, int childPosition)
			{
				return childPosition;
			}
			@Override
			public int getChildrenCount(int groupPosition)
			{
				return arms[groupPosition].length;
			}
			private TextView getTextView()
			{
				AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
						ViewGroup.LayoutParams.MATCH_PARENT, 64);
				TextView textView = new TextView(MainActivity.this);
				textView.setLayoutParams(lp);
				textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
				textView.setPadding(36, 0, 0, 0);
				textView.setTextSize(16);
				return textView;
			}
			//该方法决定每个子选项的外观
			@Override
			public View getChildView(int groupPosition, int childPosition,
					boolean isLastChild, View convertView, ViewGroup parent)
			{
				TextView textView = getTextView();
				textView.setText(getChild(groupPosition, childPosition).toString());
				return textView;
			}
			//获取指定组位置处的组数据
			@Override
			public Object getGroup(int groupPosition)
			{
				return armTypes[groupPosition];
			}
			@Override
			public int getGroupCount()
			{
				return armTypes.length;
			}
			@Override
			public long getGroupId(int groupPosition)
			{
				return groupPosition;
			}
			//该方法决定每个组选项的外观
			@Override
			public View getGroupView(int groupPosition, boolean isExpanded,
					View convertView, ViewGroup parent)
			{
				LinearLayout ll = new LinearLayout(MainActivity.this);
				ll.setOrientation(0);
				ImageView logo = new ImageView(MainActivity.this);
				logo.setImageResource(logos[groupPosition]);
				ll.addView(logo);
				TextView textView = getTextView();
				textView.setText(getGroup(groupPosition).toString());
				ll.addView(textView);
				return ll;
			}
			@Override
			public boolean isChildSelectable(int groupPosition, int childPosition)
			{
				return true;
			}
			@Override
			public boolean hasStableIds()
			{
				return true;
			}
		};
		// 设置该窗口显示列表
		setListAdapter(adapter);
	}
}
           
UI组件之AdapterView及其子类(六)ExpandableListView组件和ExpandableListActivity的使用

附上源码更方便学习:

public class ExpandableListActivity extends Activity implements
        OnCreateContextMenuListener,
        ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
        ExpandableListView.OnGroupExpandListener {   
    ExpandableListAdapter mAdapter;
    ExpandableListView mList;
    boolean mFinishedStart = false;

    /**
     * Override this to populate the context menu when an item is long pressed. menuInfo
     * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
     * whose packedPosition is a packed position
     * that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
     * the other similar methods.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    }

    /**
     * Override this for receiving callbacks when a child has been clicked.
     * <p>
     * {@inheritDoc}
     */
    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
            int childPosition, long id) {
        return false;
    }

    /**
     * Override this for receiving callbacks when a group has been collapsed.
     */
    public void onGroupCollapse(int groupPosition) {
    }

    /**
     * Override this for receiving callbacks when a group has been expanded.
     */
    public void onGroupExpand(int groupPosition) {
    }

    /**
     * Ensures the expandable list view has been created before Activity restores all
     * of the view states.
     * 
     *@see Activity#onRestoreInstanceState(Bundle)
     */
    @Override
    protected void onRestoreInstanceState(Bundle state) {
        ensureList();
        super.onRestoreInstanceState(state);
    }

    /**
     * Updates the screen state (current list and other views) when the
     * content changes.
     * 
     * @see Activity#onContentChanged()
     */
    @Override
    public void onContentChanged() {
        super.onContentChanged();
        View emptyView = findViewById(com.android.internal.R.id.empty);
        mList = (ExpandableListView)findViewById(com.android.internal.R.id.list);
        if (mList == null) {
            throw new RuntimeException(
                    "Your content must have a ExpandableListView whose id attribute is " +
                    "'android.R.id.list'");
        }
        if (emptyView != null) {
            mList.setEmptyView(emptyView);
        }
        mList.setOnChildClickListener(this);
        mList.setOnGroupExpandListener(this);
        mList.setOnGroupCollapseListener(this);
        
        if (mFinishedStart) {
            setListAdapter(mAdapter);
        }
        mFinishedStart = true;
    }

    /**
     * Provide the adapter for the expandable list.
     */
    public void setListAdapter(ExpandableListAdapter adapter) {
        synchronized (this) {
            ensureList();
            mAdapter = adapter;
            mList.setAdapter(adapter);
        }
    }

    /**
     * Get the activity's expandable list view widget.  This can be used to get the selection,
     * set the selection, and many other useful functions.
     * 
     * @see ExpandableListView
     */
    public ExpandableListView getExpandableListView() {
        ensureList();
        return mList;
    }
    
    /**
     * Get the ExpandableListAdapter associated with this activity's
     * ExpandableListView.
     */
    public ExpandableListAdapter getExpandableListAdapter() {
        return mAdapter;
    }

    private void ensureList() {
        if (mList != null) {
            return;
        }
        setContentView(com.android.internal.R.layout.expandable_list_content);
    }

    /**
     * Gets the ID of the currently selected group or child.
     * 
     * @return The ID of the currently selected group or child.
     */
    public long getSelectedId() {
        return mList.getSelectedId();
    }

    /**
     * Gets the position (in packed position representation) of the currently
     * selected group or child. Use
     * {@link ExpandableListView#getPackedPositionType},
     * {@link ExpandableListView#getPackedPositionGroup}, and
     * {@link ExpandableListView#getPackedPositionChild} to unpack the returned
     * packed position.
     * 
     * @return A packed position representation containing the currently
     *         selected group or child's position and type.
     */
    public long getSelectedPosition() {
        return mList.getSelectedPosition();
    }

    /**
     * Sets the selection to the specified child. If the child is in a collapsed
     * group, the group will only be expanded and child subsequently selected if
     * shouldExpandGroup is set to true, otherwise the method will return false.
     * 
     * @param groupPosition The position of the group that contains the child.
     * @param childPosition The position of the child within the group.
     * @param shouldExpandGroup Whether the child's group should be expanded if
     *            it is collapsed.
     * @return Whether the selection was successfully set on the child.
     */
    public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
        return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
    }

    /**
     * Sets the selection to the specified group.
     * @param groupPosition The position of the group that should be selected.
     */
    public void setSelectedGroup(int groupPosition) {
        mList.setSelectedGroup(groupPosition);
    }

}           

继续阅读