您的位置:首页 > 移动开发 > Android开发

我的学习之旅:android expandablelistview的应用

2014-03-28 20:37 477 查看
有点时候没写博客了。最近因为在写一些小项目,用到了expandablelistview这个控件,发现这个控件和之前用的listview的用法差不多。

记录一下自己的学习过程总是好的,尽管这个知识点不是很难。

expandablelistview这个控件的效果是我们应该很常见,就是类似于QQ好友分组那样的效果:



这个控件中是有两个条目的。分别是一级条目和二级条目,在点击一级条目的时候,可以显示二级条目。

在一级条目和二级条目中,我们可以自定义其样式:

一级条目样式定义:

group.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" >
<TextView
android:layout_width="fill_parent"
android:layout_height="50dp"
android:id="@+id/list_group"
android:text="group"/>

</LinearLayout>


就是定义了一个TextView。也可以将其样式改成自己想要的,如加入ImageView等

二级条目样式定义:

child.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/elistview_item">
<ImageView
android:id="@+id/person_Img"
android:layout_width="45dp"
android:layout_height="45dp"
android:background="@drawable/icon"
android:contentDescription="@string/app_name"/>
<TextView
android:id="@+id/person_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/person_Img"
android:layout_marginLeft="50dp"
android:layout_alignTop="@+id/person_Img"
android:text="@string/personName"/>
<TextView
android:id="@+id/person_post"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/person_Img"
android:layout_marginLeft="50dp"
android:layout_below="@+id/person_name"
android:text="@string/personPost"/>

</RelativeLayout>


把自己想要的样式条目定义好后就需要下一步,写一个包含expandablelistview控件的Layout

<?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:id="@+id/list_contact"
android:orientation="vertical" >
<ExpandableListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/listView">

</ExpandableListView>

</LinearLayout>


在定义好布局后就我习惯写一个类,这个类用来作一个中间变量的,用来存放每一个二级条目显示的内容:

public class PersonalData {
String person_Name ;  //姓名
String person_Post ;  //职务
Bitmap person_photo ; //个人照片

public void setPerson_Name(String person_Name){
this.person_Name = person_Name ;
}

public void setPerson_Post(String person_Post){
this.person_Post = person_Post ;
}

public void setPerson_photo(Bitmap person_photo){
this.person_photo = person_photo ;
}

public String getPerson_Name(){
return person_Name ;
}

public String getPerson_Post(){
return person_Post ;
}

public Bitmap getPerson_photo(){
return person_photo ;
}
}


下面一个Activity,来显示自己定义的expandablelistview:

public class Contact extends Activity {

String _groupname[] =null; //每一组对应的组名
String _postname[] = null; //每一组对应下的子项显示的职务名称
String _NameData[][] = null; //每一组对应下的子项显示的姓名
String _describe[] =null;	//描述
int _PhotoData[][] = null;  //子项姓名对应的照片的ID

private ExpandableListView _eListView = null;
private ArrayList<String> _listGroup = new ArrayList<String>();
private ArrayList<ArrayList<PersonalData>> _listItems= new ArrayList<ArrayList<PersonalData>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contact);

initData();
getPerson();
getView();
}

private void initData(){
_describe = new String[]{"姓名:","职务:"};
_groupname =new String[]{"2014级教务员","2014级辅导员","14级计算机1班","14级计算机2班","14级计算机3班","14级软件工程1班"
,"14级软件工程2班","14级软件工程3班","14级网络工程1班","14级网络工程2班","14级网络工程3班"};
_postname = new String[]{"教务员","辅导员","班主任","班主任助理","临时班干"};
_NameData = new String[][]{{"教务员姓名"},{"辅导员姓名"},
{"计1班主任姓名","计1班主任助理","临时班干1","临时班干2","临时班干3"},
{"计2班主任姓名","计2班主任助理","临时班干1","临时班干2","临时班干3"},
{"计3班主任姓名","计3班主任助理","临时班干1","临时班干2","临时班干3"},
{"软1班主任姓名","软1班主任助理","临时班干1","临时班干2","临时班干3"},
{"软2班主任姓名","软2班主任助理","临时班干1","临时班干2","临时班干3"},
{"软3班主任姓名","软3班主任助理","临时班干1","临时班干2","临时班干3"},
{"网1班主任姓名","网1班主任助理","临时班干1","临时班干2","临时班干3"},
{"网2班主任姓名","网2班主任助理","临时班干1","临时班干2","临时班干3"},
{"网3班主任姓名","网3班主任助理","临时班干1","临时班干2","临时班干3"}};
_PhotoData =new int[][]{{R.drawable.icon},{R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon},
{R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon,R.drawable.icon}};
}

private void getView(){
_eListView = (ExpandableListView) findViewById(R.id.listView);
ExpandableAdapter adapter = new ExpandableAdapter(this, _listGroup, _listItems);
_eListView.setAdapter(adapter);
_eListView.setOnChildClickListener(new Listener());
}

private void getPerson(){
for(int i=0 ; i < _groupname.length ; i++){
_listGroup.add(_groupname[i]);
}
for(int i = 0 ; i < _NameData.length ; i++){
ArrayList<PersonalData> _items = new ArrayList<PersonalData>();
for(int j = 0 ; j < _NameData[i].length ; j++){
PersonalData person = new PersonalData();
person.setPerson_Name(_describe[0]+_NameData[i][j]);
person.setPerson_photo((BitmapFactory.decodeResource(getResources(),
_PhotoData[i][j])));
if(i == 0 && j== 0){
person.setPerson_Post(_describe[1]+_postname[0]);
}else if(i == 1 && j == 0){
person.setPerson_Post(_describe[1]+_postname[1]);
}else if(i != 0 && i != 1){
if(j == 0){
person.setPerson_Post(_describe[1]+_postname[2]);
}else if(j == 1){
person.setPerson_Post(_describe[1]+_postname[3]);
}else{
person.setPerson_Post(_describe[1]+_postname[4]);
}
}
_items.add(person);
}
_listItems.add(_items);
}
}


在initData()方法当中定义好了自己需要的数据,当然,你也可以连接你的数据库,来提取你需要的数据。

在getView()方法当中找到自己在Layout中定义的expandablelistview的,可以通过findViewById,初始化expandablelistview,给expandablelistview绑定Adapter和点击监听器。

而这个getPerson()这个方法是很重要的,在这里用到了我之前定义的中间类,在这个Activity中我定义了两个ArrayList,一个是用来装载一级条目内容的;另一个是用来装载二级条目的,因为expandablelistview还是继承listview嘛,所以当然少不了使用list咯。可以再代码中看到一个ArrayList填入的是一个String,另一个填入的是一个list,没错,就是在一个list当中嵌套另外一个list,而被嵌套的那个list填入的是自己定义的Person类。

好,那我们来仔细看看这个方法中的代码:第一个for循环中是填充用来装载一级条目的ArrayList,具体的数据已经在initData方法当中写入了;第二个for循环当然是填充用来装载二级条目内容的ArrayList啦,而每次填充进去的都是一个Person类的对象。

我们在initData方法中给expandablelistview绑定的Adapter是自己定义的:

public class ExpandableAdapter extends BaseExpandableListAdapter {
private ArrayList<ArrayList<PersonalData>> _listitems = new ArrayList<ArrayList<PersonalData>>();
private ArrayList<String> _listGroup = new ArrayList<String>();
private LayoutInflater _Inflater = null;
private ItemDemo _itemdemo = new ItemDemo();
private GroupDemo _groupdemo = new GroupDemo();

public ExpandableAdapter(Context context,ArrayList<String> _listGroup,ArrayList<ArrayList<PersonalData>> _listitems){
this._listitems = _listitems ;
this._listGroup = _listGroup ;
_Inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return _listitems.get(groupPosition).get(childPosition);
}

@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return 0;
}

@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
convertView = _Inflater.inflate(R.layout.elistview_item, null);
if(convertView == null || childPosition < _listitems.size() || groupPosition < _listGroup.size()){
_itemdemo._imageView = (ImageView) convertView.findViewById(R.id.person_Img);
_itemdemo._nameView = (TextView) convertView.findViewById(R.id.person_name);
_itemdemo._postView = (TextView) convertView.findViewById(R.id.person_post);
}else{
_itemdemo = (ItemDemo) convertView.getTag();
}
_itemdemo._nameView.setText(_listitems.get(groupPosition).get(childPosition).getPerson_Name());
_itemdemo._postView.setText(_listitems.get(groupPosition).get(childPosition).getPerson_Post());
_itemdemo._imageView.setImageBitmap(_listitems.get(groupPosition).get(childPosition).getPerson_photo());
return convertView;
}

@Override
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
return _listitems.get(groupPosition).size();
}

@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return _listGroup.get(groupPosition);
}

@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return _listGroup.size();
}

@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
convertView = _Inflater.inflate(R.layout.elistview_group, null);
if(convertView == null || groupPosition < _listGroup.size()){
_groupdemo._groupName = (TextView) convertView.findViewById(R.id.list_group);
}else{
_groupdemo = (GroupDemo) convertView.getTag();
}
_groupdemo._groupName.setText(_listGroup.get(groupPosition).toString());
return convertView;
}

@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}

public class ItemDemo{
public ImageView _imageView = null;
public TextView _nameView = null;
public TextView _postView = null;
}

public class GroupDemo{
public TextView _groupName = null;
}
}


这个Adapter是继承BaseExpandablelistAdapter的。

BaseExpandableListAdapter的主要重载方法如下:

public abstract Object getChild (int groupPosition, int childPosition)

取得与指定分组、指定子项目关联的数据.

参数

groupPosition 包含子视图的分组的位置.

childPosition 指定的分组中的子视图的位置.

返回

与子视图关联的数据.

public abstract long getChildId (int groupPosition, intchildPosition)

取得给定分组中给定子视图的ID. 该组ID必须在组中是唯一的.必须不同于其他所有ID(分组及子项目的ID).

参数

groupPosition 包含子视图的分组的位置.

childPosition 要取得ID的指定的分组中的子视图的位置.

返回

与子视图关联的ID.

public abstract View getChildView (int groupPosition, intchildPosition, boolean isLastChild, View convertView, ViewGroup parent)

取得显示给定分组给定子位置的数据用的视图.

参数

groupPosition 包含要取得子视图的分组位置.

childPosition 分组中子视图(要返回的视图)的位置.

isLastChild 该视图是否为组中的最后一个视图.

convertView 如果可能,重用旧的视图对象.使用前你应该保证视图对象为非空,并且是否是合适的类型.如果该对象不能转换为可以正确显示数据的视图,该方法就创建新视图.不保证使用先前由 getChildView(int, int,boolean, View, ViewGroup)创建的视图.

parent 该视图最终从属的父视图.

返回

指定位置相应的子视图.

public abstract int getChildrenCount (int groupPosition)

取得指定分组的子元素数.

参数

groupPosition 要取得子元素个数的分组位置.

返回

指定分组的子元素个数,这个返回分组子元素数很重要,是判定显示的子元素的多少的重要依据.

public abstract long getCombinedChildId (long groupId, long childId)

取得一览中可以唯一识别子条目的 ID(包括分组ID和子条目ID).可扩展列表要求每个条目 (分组条目和子条目)具有一个可以唯一识别列表中子条目和分组条目的ID. 该方法根据给定子条目ID和分组条目ID返回唯一识别ID.另外,如果 hasStableIds() 为真,该函数返回的ID必须是固定不变的.

参数

groupId 包含子条目ID的分组条目ID.

childId 子条目的ID.

返回

可以在所有分组条目和子条目中唯一识别该子条目的ID(可能是固定不变的).

public abstract long getCombinedGroupId (long groupId)

取得一览中可以唯一识别子条目的 ID(包括分组ID和子条目ID).可扩展列表要求每个条目 (分组条目和子条目)具有一个可以唯一识别列表中子条目和分组条目的ID. 该方法根据给定子条目ID和分组条目ID返回唯一识别ID.另外,如果 hasStableIds() 为真,该函数返回的ID必须是固定不变的.

参数

groupId 分组条目ID.

返回

可以在所有分组条目和子条目中唯一识别该分组条目的ID(可能是固定不变的).

public abstract Object getGroup (int groupPosition)

取得与给定分组关联的数据.

参数

groupPosition 分组的位置.

返回

指定分组的数据.

public abstract int getGroupCount ()

取得分组数.

返回

分组数.

public abstract long getGroupId (int groupPosition)

取得指定分组的ID.该组ID必须在组中是唯一的.必须不同于其他所有ID(分组及子项目的ID).

参数

groupPosition 要取得ID的分组位置.

返回

与分组关联的ID.

public abstract View getGroupView (int groupPosition, booleanisExpanded, View convertView, ViewGroup parent)

取得用于显示给定分组的视图. 这个方法仅返回分组的视图对象, 要想获取子元素的视图对象,就需要调用 getChildView(int, int, boolean, View, ViewGroup).

参数

groupPosition 决定返回哪个视图的组位置 .

isExpanded 该组是展开状态还是收起状态 .

convertView 如果可能,重用旧的视图对象.使用前你应该保证视图对象为非空,并且是否是合适的类型.如果该对象不能转换为可以正确显示数据的视图,该方法就创建新视图.不保证使用先前由 getGroupView(int, boolean,View, ViewGroup)创建的视图.

parent 该视图最终从属的父视图.

返回

指定位置相应的组视图.

public abstract boolean hasStableIds ()

是否指定分组视图及其子视图的ID对应的后台数据改变也会保持该ID.

返回

是否相同的ID总是指向同一个对象.

public abstract boolean isChildSelectable (int groupPosition, intchildPosition)

指定位置的子视图是否可选择.

参数

groupPosition 包含要取得子视图的分组位置.

childPosition 分组中子视图的位置.

返回
是否子视图可选择

参考完了那些需要实现的方法和具体参数含义后,看看写在其中的两个内部类:ItemDemo和GroupDemo,这两个内部类也是起到一个中间类的作用,前面定义的一级条目和二级条目的布局总得有一个变量来指向它们,不然怎么知道数据填充的位置是在我们定义好的布局中呢。

好了,中间类是写好了,问题是在哪里使用它们呢。。。看看代码就知道,就是我们需要实现的getGroupView和getChildView当中。

在getGroupView中怎么获取到我们定义的布局的ID:

convertView = _Inflater.inflate(R.layout.elistview_group, null);
这样就可以找到啦,但是为了保险起见,万一没获取到我们就可以:
if(convertView == null || groupPosition < _listGroup.size()){
_groupdemo._groupName = (TextView) convertView.findViewById(R.id.list_group);
}

还有一个就是
_groupdemo = (GroupDemo) convertView.getTag();


这句代码的意思是把convertView代表的布局文件给demo,等于demo和convertView共同使用一个布局控件。

同样,getChildView的实现也是一样的。

好了这样就基本上实现了条目的填充了,可以在手机上显示咯。

另外,要改变每个组前面的图标,并且图标样式随着合拢和展开不同,则只需要在res/drawable目录下定义文件:Indicator.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_expanded="true" android:drawable="@drawable/right" />
<item android:drawable="@drawable/down"></item>
</selector>


然后在Activity中:

myExpandableListView.setGroupIndicator(this.getResources().getDrawable(R.drawable.indicator));


对于其他的属性设置,可以参考以下属性说明:

android:childDivider

来分离子列表项的图片或者是颜色。注:图片不会完全显示,分离子列表项的是一条直线

android:childIndicator

在子列表项旁边显示的指示符。注:可以是一个图片

android:childIndicatorLeft

子列表项指示符的左边约束位置。注:即从左端0位置开始计数,比如,假设指示符是一个图标,给定这个属性值为3dip,则表示从左端起3dip开始显示此图标。

android:childIndicatorRight

子列表项指示符的右边约束位置。注:表示右端到什么位置结束

android:groupIndicator

在组列表项旁边显示的指示符。注:可以是一个图片。

android:indicatorLeft

组列表项指示器的左边约束位置。注:表示左端从什么位置开始。

android:indicatorRight

组列表项指示器的右边约束位置。注:表示右端到什么位置结束。

还有一个就是二级条目的点击事件咯:

class Listener implements ExpandableListView.OnChildClickListener{

@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
System.out.println("group--->"+groupPosition+"\nchild----->"+childPosition);
if(groupPosition == 0 && childPosition == 0){
Intent intent = new Intent();
intent.setClass(Contact.this, PersonInfo.class);
startActivity(intent);}}


这个很简单,不解释....

文章的编写有些是参考网上的,都是在学习路上.....
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: