Android开发系列(九) ExpandableListView进阶使用——QQ联系人列表(升级版)
本节继续讲ExpandableListView的使用,与系列(六)中类似,这里需要写一个自定义的适配器类继承BaseExpandableListAdapter, 并且对QQ联系人列表进行升级,使之具有对联系人分类的功能,即可以分成"我的好友","朋友","陌生人"等等类别。如果对第六节的内容给比较熟悉,可以完全根据那个思路构造出自己的适配器类,实际上我在写这节内容之前并没有参考网上的资料慢慢摸索出来的。
首先是布局文件,
activity_main.xml 主布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="#00aaff" tools:context=".MainActivity" > <TextView android:id="@+id/myText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="联系人" android:textSize="7pt" android:layout_centerHorizontal="true" android:textColor="#ffffff" android:textStyle="bold" /> <ExpandableListView android:id="@+id/qq_list" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/myText" android:divider="#888888" android:dividerHeight="0.15px"/> </RelativeLayout>
一级条目的布局文件 layout_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="wrap_content" android:paddingLeft="5dip" android:orientation="horizontal" android:background="#eeeeee"> <ImageView android:id="@+id/groupImage" android:layout_width="match_parent" android:layout_height="15dip" android:layout_weight="1.8" android:layout_gravity="center" /> <TextView android:id="@+id/groupName" android:layout_width="match_parent" android:layout_height="30dip" android:layout_weight="1" android:paddingLeft="15dip" android:paddingTop="5dip" android:textSize="7pt" android:text="fdg" /> <TextView android:id="@+id/childCount" android:layout_width="match_parent" android:layout_height="30dip" android:layout_weight="1" android:gravity="right" android:paddingRight="10dip" android:paddingTop="5dip" android:text="ewsf"/> </LinearLayout>
二级条目的布局文件layout_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="wrap_content" android:background="#efefef" > <!-- LinerLayout有比较奇怪的性质:当布局中的控件可以超出布局规定的大小 ,所以这里一行的行宽改成由内部的几个控件 控制,而LinerLayout的layout_height改成wrap_content .. --> <ImageButton android:id="@+id/ct_photo" android:layout_height="70dip" android:layout_width="70dip" android:layout_margin="5dip"/> <TextView android:id="@+id/ct_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dip" android:layout_toRightOf="@id/ct_photo" android:layout_alignTop="@id/ct_photo" android:text="为你我受冷风吹" android:textSize="8pt" android:textStyle="bold" android:maxLength="7"/> <TextView android:id="@+id/ct_sign" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dip" android:layout_toRightOf="@id/ct_photo" android:layout_alignBottom="@id/ct_photo" android:text="为什么受伤的总是我" android:textColor="#888888"/> <!-- 注意不是layout_padding --> </RelativeLayout>
下面就是自定义的适配器类,为了和Simple适配器参数相同,这里采用了类似的构造函数。
package com.example.android_baseexpandablelistview; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.*; import java.util.*; public class MyAdapter extends BaseExpandableListAdapter{ private Context context=null; private ArrayList<HashMap<String,Object>> groupData=null; int groupLayout=0; private String[] groupFrom=null; private int[] groupTo=null; private ArrayList<ArrayList<HashMap<String,Object>>> childData=null; int childLayout=0; private String[] childFrom=null; private int[] childTo=null; public MyAdapter(Context context, ArrayList<HashMap<String, Object>> groupData, int groupLayout, String[] groupFrom, int[] groupTo, ArrayList<ArrayList<HashMap<String, Object>>> childData, int childLayout, String[] childFrom, int[] childTo) { super(); this.context = context; this.groupData = groupData; this.groupLayout = groupLayout; this.groupFrom = groupFrom; this.groupTo = groupTo; this.childData = childData; this.childLayout = childLayout; this.childFrom = childFrom; this.childTo = childTo; } @Override public Object getChild(int arg0, int arg1) { // TODO Auto-generated method stub return null; } /** * position与id一样,都是从0开始计数的, * 这里返回的id也是从0开始计数的 */ @Override public long getChildId(int groupPosition, int childPosition) { // TODO Auto-generated method stub long id=0; for(int i=0;i<groupPosition; i++){ id+=childData.size(); } id+=childPosition; return id; } /**ChildViewHolder内部类**/ class ChildViewHolder{ ImageButton userImage=null; TextView userName=null; TextView userSign=null; } /**头像点击事件监听类**/ class ImageClickListener implements OnClickListener{ ChildViewHolder holder=null; public ImageClickListener(ChildViewHolder holder){ this.holder=holder; } @Override public void onClick(View v) { // TODO Auto-generated method stub Toast.makeText(context, holder.userName.getText()+" is clicked", Toast.LENGTH_SHORT).show(); } } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { // TODO Auto-generated method stub /** * 这里isLastChild目前没用到,如果出现异常再说 */ ChildViewHolder holder=null; if(convertView==null){ convertView= LayoutInflater.from(context).inflate(childLayout,null); //感觉这里需要把root设置成ViewGroup 对象 /** * ERROR!!这里不能把null换成parent,否则会出现异常退出,原因不太确定,可能是inflate方法获得的这个item的View * 并不属于某个控件组,所以使用默认值null即可 */ holder=new ChildViewHolder(); holder.userImage=(ImageButton)convertView.findViewById(childTo[0]); holder.userName=(TextView)convertView.findViewById(childTo[1]); holder.userSign=(TextView)convertView.findViewById(childTo[2]); convertView.setTag(holder); } else{ holder=(ChildViewHolder)convertView.getTag(); } holder.userImage.setBackgroundResource((Integer)(childData.get(groupPosition).get(childPosition).get(childFrom[0]))); holder.userName.setText(childData.get(groupPosition).get(childPosition).get(childFrom[1]).toString()); holder.userSign.setText(childData.get(groupPosition).get(childPosition).get(childFrom[2]).toString()); holder.userImage.setOnClickListener(new ImageClickListener(holder)); return convertView; } @Override public int getChildrenCount(int groupPosition) { // TODO Auto-generated method stub return childData.get(groupPosition).size(); } @Override public Object getGroup(int groupPosition) { // TODO Auto-generated method stub return null; } @Override public int getGroupCount() { // TODO Auto-generated method stub return groupData.size(); } @Override public long getGroupId(int groupPosition) { // TODO Auto-generated method stub return groupPosition; } class GroupViewHolder{ ImageView image=null; TextView groupName=null; TextView childCount=null; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // TODO Auto-generated method stub GroupViewHolder holder=null; if(convertView==null){ convertView=LayoutInflater.from(context).inflate(groupLayout, null); holder=new GroupViewHolder(); holder.image=(ImageView)convertView.findViewById(groupTo[0]); holder.groupName=(TextView)convertView.findViewById(groupTo[1]); holder.childCount=(TextView)convertView.findViewById(groupTo[2]); convertView.setTag(holder); } else{ holder=(GroupViewHolder)convertView.getTag(); } int[] groupIndicator=(int[])groupData.get(groupPosition).get(groupFrom[0]); holder.image.setBackgroundResource(groupIndicator[isExpanded?1:0]); holder.groupName.setText(groupData.get(groupPosition).get(groupFrom[1]).toString()); holder.childCount.setText(groupData.get(groupPosition).get(groupFrom[2]).toString()); return convertView; /** * 不要在适配器中调用适配器的内部方法,不然会出现奇怪的异常 * */ } @Override public boolean hasStableIds() { // TODO Auto-generated method stub return false; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { // TODO Auto-generated method stub return true; } }
由上一节的内容可知为适配器添加数据非常麻烦,因此这里创建了一个 QQ用户类,用来存放一个QQ用户的各种信息,然后在MainActivity中设计了一个将新QQ用户对象添加进List数据链表中的方法,见下面:
package com.qqlist.contactor; public class UserInfo { public String userName=null; public String userSign=null; public int userImage=0; public String groupInfo=null; public UserInfo(String userName, String userSign, int userImage, String groupInfo) { super(); this.userName = userName; this.userSign = userSign; this.userImage = userImage; this.groupInfo = groupInfo; } }
然后是MainActivity
package com.example.android_baseexpandablelistview; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.ExpandableListView; import java.util.*; import com.qqlist.contactor.UserInfo; public class MainActivity extends Activity { int[] photoRes={R.drawable.contact_0,R.drawable.contact_1,R.drawable.contact_2,R.drawable.contact_3}; String[] groupFrom={"groupImage","groupName","childCount"}; int[] groupTo={R.id.groupImage,R.id.groupName,R.id.childCount}; String[] childFrom={"userImage","userName","userSign"}; int[] childTo={R.id.ct_photo,R.id.ct_name,R.id.ct_sign}; ArrayList<HashMap<String,Object>> groupData=null; ArrayList<ArrayList<HashMap<String,Object>>> childData=null; int[] groupIndicator={R.drawable.toright,R.drawable.todown}; ExpandableListView list=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); groupData=new ArrayList<HashMap<String,Object>>(); childData=new ArrayList<ArrayList<HashMap<String,Object>>> (); UserInfo user1=new UserInfo("暗夜之殇","总有一天会寻找到自己的幸福",R.drawable.contact_0,"我的好友"); UserInfo user2=new UserInfo("街角的幸福","有些事终于想开了",R.drawable.contact_1,"我的好友"); UserInfo user3=new UserInfo("愤怒的小胖","谁再叫我小胖我跟谁急!",R.drawable.contact_3,"朋友"); UserInfo user4=new UserInfo("放羊的星星","What ever",R.drawable.contact_2,"陌生人"); addUser(user1); addUser(user2); addUser(user3); addUser(user4); //不能用HashMap的实参赋给Map形参,只能new一个HashMap对象赋给Map的引用! MyAdapter adapter=new MyAdapter(this,groupData,R.layout.layout_group,groupFrom,groupTo,childData,R.layout.layout_child,childFrom,childTo ); list=(ExpandableListView)findViewById(R.id.qq_list); list.setAdapter(adapter); list.setGroupIndicator(null); } protected void addUser(UserInfo user) { int i; for(i=0; i< groupData.size(); i++){ if(groupData.get(i).get("groupName").toString().equals(user.groupInfo)){ break; } } if(i>=groupData.size()){ HashMap<String,Object> map=new HashMap<String,Object>(); map.put("groupImage", groupIndicator); map.put("groupName",user.groupInfo ); map.put("childCount", 0); groupData.add(map); ArrayList<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>(); childData.add(list); } HashMap<String,Object> userData=new HashMap<String,Object>(); userData.put("userImage",user.userImage ); userData.put("userName", user.userName); userData.put("userSign", user.userSign); childData.get(i).add(userData); Integer count=(Integer)groupData.get(i).get("childCount")+1; groupData.get(i).put("childCount", count); } }
有些代码是为了美化界面用的不必深究。
下面附上效果图:
几点总结:
1、在getChildView方法中,要使用inflate()方法,注意该方法的第二个参数一般为null,不用考虑为parent的情况
2、在适配器类中最好不要调用适配器的类方法,那些方法是系统在绘制View时使用的,乱用会导致异常
3、Java语法:可以使用new
方法创建一个普通类(HashMap)赋值给接口类(Map),但普通类对象不能作为实参传递给接口类形参。
4、如果想去掉ListView的分割线,必须同时设定
android:divider="#aaaaaa" <!--颜色-->
android:dividerHeight="0px"
前者可以让分割线变成无边框的矩形,然后调节成0像素使分割线消失。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。