先上个效果图:
1,我用的fragment
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.dami.student.ui.chatui.adapter.ContactsExpandableListAdapter;
import com.dami.student.R;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.dami.student.entity.AccountInformation;
import android.widget.ExpandableListView;
import com.dami.student.entity.ClassEntity;
import com.dami.student.entity.ClassMembers;
import com.dami.student.net.database.OperationDB;
import com.dami.student.net.socket.SendDataSocketInterface;
import com.dami.student.net.socket.SocketService;
import com.dami.student.net.utils.BusinessCallbackBase;
import com.dami.student.net.utils.BusinessCallbackInterfaceUtil;
import com.dami.student.net.utils.CommandPackage;
import com.dami.student.net.utils.LogUtil;
import com.dami.student.ui.chatui.adapter.SortClassMemberAdapter;
import com.dami.student.ui.chatui.ui.activity.PrivateChatActivity;
import com.dami.student.ui.chatui.util.CharacterParser;
import com.dami.student.ui.chatui.util.ClearEditText;
import com.dami.student.ui.chatui.util.PinyinComparator;
import android.widget.ExpandableListView.OnChildClickListener;public class ContactsFragmentExpandableListView extends Fragment {private boolean isDebug = true;private String TAG = "ContactsFragmentExpandableListView";private ContactsEntityBusinessCallback mContactsEntityBusinessCallback;private View contactsFragmentView;private Context mContext;private List<List<?>> mGroupMemberList = new ArrayList<List<?>>();//群组名称 private String[] mGroup = new String[] { "家庭群", "班级群"};private List<AccountInformation> mAccountInformationList = new ArrayList<AccountInformation>();private ExpandableListView mExpandableListView;private List<ClassMembers> mClassMembersList;private ContactsExpandableListAdapter mContactsExpandableListAdapter;public ClearEditText mClearEditText;private ClassEntity mClassEntity;private int sequence;private byte[] data;private boolean flag;/*** 汉字转换成拼音的类*/private CharacterParser characterParser;/*** 根据拼音来排列ListView里面的数据类*/private PinyinComparator pinyinComparator;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// TODO Auto-generated method stubcontactsFragmentView = inflater.inflate(R.layout.fragment_contacts_expandablelistview,container, false);findViewById();inIt();return contactsFragmentView;}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();BusinessCallbackInterfaceUtil.remove(mContactsEntityBusinessCallback);}private Handler mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case 1:// 根据a-z进行排序//mClassMembersList = filledData(mClassMembersList);mGroupMemberList.clear();LogUtil.i(TAG, "wdh handleMessage"+mAccountInformationList);mGroupMemberList.add(mAccountInformationList);mGroupMemberList.add(mClassMembersList);mContactsExpandableListAdapter.updateExpandableListView(mGroup,mGroupMemberList);for (int i = 0; i < mClassMembersList.size(); i++) {OperationDB.getInstance(mContext).setClassMenberEntity(mClassMembersList.get(i));}break;default:break;}};};private void findViewById() {// TODO Auto-generated method stubmExpandableListView = (ExpandableListView) contactsFragmentView.findViewById(R.id.group_expandableListView);mClearEditText = (ClearEditText) getActivity().findViewById(R.id.filter_edit);}private void inIt() {// TODO Auto-generated method stub// 实例化汉字转拼音类characterParser = CharacterParser.getInstance();pinyinComparator = new PinyinComparator();mContext = getActivity();mClassEntity = OperationDB.getInstance(mContext).QueryClassEntity();mAccountInformationList.addAll(0, OperationDB.getInstance(mContext).getUserData(0));mAccountInformationList.addAll(1, OperationDB.getInstance(mContext).getUserData(1));mGroupMemberList.add(mAccountInformationList);if (mClassEntity.className != null) {mClassMembersList = filledData(OperationDB.getInstance(mContext).QueryClassMenberEntity(1,mClassEntity.classId,mClassEntity.classId));if (null != mClassMembersList && mClassMembersList.size() != 0) {mGroupMemberList.add(mClassMembersList);}}LogUtil.i(TAG, "wdh mGroupMemberList "+mGroupMemberList.size());LogUtil.i(TAG, "wdh mGroupMemberList "+mGroupMemberList);mContactsExpandableListAdapter = new ContactsExpandableListAdapter(mContext,mGroup,mGroupMemberList);mExpandableListView.setAdapter(mContactsExpandableListAdapter);mExpandableListView.setGroupIndicator(null);mExpandableListView.setOnChildClickListener(new OnChildClickListener() {@Overridepublic boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {// TODO Auto-generated method stubObject object = mGroupMemberList.get(groupPosition).get(childPosition);LogUtil.i(TAG, "wdh --onChildClick---- "+object);Intent intent = new Intent(mContext, PrivateChatActivity.class);if (object instanceof ClassMembers) {intent.putExtra("object", (ClassMembers)object);startActivity(intent);}else if (object instanceof AccountInformation) {ClassMembers classMembers = new ClassMembers();AccountInformation mAccountInformation = (AccountInformation)object;classMembers.setMemberId(mAccountInformation.getUserId());classMembers.setName(mAccountInformation.getUserName());classMembers.setPhone(mAccountInformation.getPhoneNum());classMembers.setHeadImg(mAccountInformation.getHeadPortrait());classMembers.setRelation(mAccountInformation.getRelation());intent.putExtra("object", classMembers);startActivity(intent);}return false;}});mContactsEntityBusinessCallback = new ContactsEntityBusinessCallback();BusinessCallbackInterfaceUtil.setCallBack(mContactsEntityBusinessCallback);// 根据输入框输入值的改变来过滤搜索mClearEditText.addTextChangedListener(new TextWatcher() {@Overridepublic void onTextChanged(CharSequence s, int start, int before,int count) {// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表filterData(s.toString());}@Overridepublic void beforeTextChanged(CharSequence s, int start, int count,int after) {}@Overridepublic void afterTextChanged(Editable s) {}});LogUtil.i(TAG, "wdh mClassEntity.classId =" + mClassEntity.classId);sequence = SocketService.getSequence();data = CommandPackage.getInstance().queryClass(sequence,mClassEntity.classId, 0);flag = SendDataSocketInterface.sendCallBack(data, 0);if (isDebug) {Log.i(TAG,"===wdh==getDeviceId====="+ OperationDB.getInstance(getActivity()).getDeviceId() + "sequence==" + sequence+ "==flag====" + flag + " mClassEntity.classId "+ mClassEntity.classId);}}/*** 为ListView填充数据* * @param date* @return*/private List<ClassMembers> filledData(List<ClassMembers> classMembersList) {if (classMembersList.size() > 0) {for (int i = 0; i < classMembersList.size(); i++) {classMembersList.get(i).setName(classMembersList.get(i).getName());// 汉字转换成拼音String pinyin = characterParser.getSelling(classMembersList.get(i).getName());String sortString = pinyin.substring(0, 1).toUpperCase();// 正则表达式,判断首字母是否是英文字母if (sortString.matches("[A-Z]")) {classMembersList.get(i).setSortLetters(sortString.toUpperCase());} else {classMembersList.get(i).setSortLetters("#");}}}return classMembersList;}/*** 根据输入框中的值来过滤数据并更新ListView* * @param filterStr*/private void filterData(String filterStr) {if (null == mClassMembersList || mClassMembersList.size() < 1) {//无数据,不搜索return;}List<ClassMembers> filterDateList = new ArrayList<ClassMembers>();if (TextUtils.isEmpty(filterStr)) {filterDateList = mClassMembersList;} else {filterDateList.clear();for (ClassMembers classMembers : mClassMembersList) {String name = classMembers.getName();if (name.indexOf(filterStr.toString()) != -1|| characterParser.getSelling(name).startsWith(filterStr.toString())) {filterDateList.add(classMembers);}}}// 根据a-z进行排序Collections.sort(filterDateList, pinyinComparator);mGroupMemberList.add(mClassMembersList);mContactsExpandableListAdapter.updateExpandableListView(mGroup,mGroupMemberList);}class ContactsEntityBusinessCallback extends BusinessCallbackBase {@Overridepublic void onClassMenbers(int result,ArrayList<ClassMembers> contactsList, int sequence) {// TODO Auto-generated method stubsuper.onClassMenbers(result, contactsList, sequence);Log.i(TAG, "wdh ===contactsList.size()===" + contactsList.size());if (0 == result) {if (isDebug)Log.i(TAG, "wdh contactsList:" + contactsList);mClassMembersList = contactsList;Message message = Message.obtain();message.what = 1;mHandler.sendMessage(message);}}}}
2,adapter,当然是继承BaseExpandableListAdapter
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.dami.student.net.socket.SocketService;
import com.dami.student.entity.AccountInformation;
import com.bumptech.glide.Glide;
import android.content.Intent;
import android.net.Uri;
import com.dami.student.R;
import com.dami.student.net.utils.LogUtil;
import com.dami.student.entity.ClassMembers;
import com.dami.student.ui.chatui.widget.CircleImageView;public class ContactsExpandableListAdapter extends BaseExpandableListAdapterimplements OnClickListener {private String Tag = "ContactsExpandableListAdapter";private String[] mGroup;// 大组组名private List<List<?>> mGroupMemberList; // 小组List,群组成员,可以使不同list,例如List<联系人>,List<家庭群>都可以放里面private Context mContext;private LayoutInflater mInflater;private int mGroupPosition;public ContactsExpandableListAdapter(Context context, String[] group,List<List<?>> groupMemberList) {this.mContext = context;this.mGroup = group;this.mGroupMemberList = groupMemberList;}public void updateExpandableListView(String[] group,List<List<?>> groupMemberList) {this.mGroup = group;this.mGroupMemberList = groupMemberList;notifyDataSetChanged();}//得到大组成员总数@Overridepublic int getGroupCount() {// TODO Auto-generated method stubreturn mGroup.length;}//得到小组成员的数量 @Overridepublic int getChildrenCount(int groupPosition) {// TODO Auto-generated method stubreturn mGroupMemberList.get(groupPosition).size();}//得到大组成员对象@Overridepublic Object getGroup(int groupPosition) {// TODO Auto-generated method stubreturn mGroup[groupPosition];}//得到小组成员对象@Overridepublic Object getChild(int groupPosition, int childPosition) {// TODO Auto-generated method stubreturn mGroupMemberList.get(groupPosition).get(childPosition);}//得到大组成员对象id@Overridepublic long getGroupId(int groupPosition) {// TODO Auto-generated method stubreturn groupPosition;}//得到小组成员对象id@Overridepublic long getChildId(int groupPosition, int childPosition) {// TODO Auto-generated method stubreturn childPosition;}/** * Indicates whether the child and group IDs are stable across changes to the * underlying data. * 表明大組和小组id是否稳定的更改底层数据。 * @return whether or not the same ID always refers to the same object * @see Adapter#hasStableIds() */@Overridepublic boolean hasStableIds() {// TODO Auto-generated method stubreturn false;}// 设置子列表是否可选中,保存groupPosition以便child里面的item里面的button写点击事件@Overridepublic boolean isChildSelectable(int groupPosition, int childPosition) {// TODO Auto-generated method stubLogUtil.i(Tag, "wdh groupPosition ="+groupPosition);mGroupPosition = groupPosition;return true;}//得到大组成员的view @Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {// TODO Auto-generated method stubViewHolderGroup groupHolder;if (null == convertView) {convertView = mInflater.from(mContext).inflate(R.layout.expandableliseview_grorp_item, parent, false);groupHolder = new ViewHolderGroup();groupHolder.group_name_tv = (TextView) convertView.findViewById(R.id.group_name_TV);groupHolder.open_close_group_IM = (ImageView) convertView.findViewById(R.id.open_close_group_IM);convertView.setTag(groupHolder);} else {groupHolder = (ViewHolderGroup) convertView.getTag();}groupHolder.open_close_group_IM.setImageResource(isExpanded ? R.drawable.open_group:R.drawable.close_group);groupHolder.group_name_tv.setText(mGroup[groupPosition]);return convertView;}//得到小组成员的view @Overridepublic View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {// TODO Auto-generated method stubViewHolderChild childHolder;if (null == convertView) {convertView = mInflater.from(mContext).inflate(R.layout.item_class_member, parent, false);childHolder = new ViewHolderChild();childHolder.tvTitle = (TextView) convertView.findViewById(R.id.title);childHolder.contactsPic = (CircleImageView) convertView.findViewById(R.id.contactsPic);childHolder.sendShortMessageIB = (ImageButton) convertView.findViewById(R.id.send_short_message_IB);childHolder.phoneIB = (ImageButton) convertView.findViewById(R.id.phone_IB);convertView.setTag(childHolder);} else {childHolder = (ViewHolderChild) convertView.getTag();}childHolder.sendShortMessageIB.setTag(R.id.send_short_message_IB,childPosition);childHolder.sendShortMessageIB.setOnClickListener(this);childHolder.phoneIB.setTag(R.id.phone_IB, childPosition);childHolder.phoneIB.setOnClickListener(this);LogUtil.i(Tag, "wdh ------groupPosition "+groupPosition);Object object = mGroupMemberList.get(groupPosition).get(childPosition);LogUtil.i(Tag, "wdh ------object "+object);if (null != object) {if (object instanceof ClassMembers) {if (null == ((ClassMembers) object).getHeadImg()) {childHolder.contactsPic.setImageResource(R.drawable.group_member_icon_default);} else {childHolder.contactsPic.setImageResource(R.drawable.group_member_icon_default);}if (((ClassMembers) object).getRelation() != null&& ((ClassMembers) object).getRelation().trim().length() > 0) {childHolder.tvTitle.setText(((ClassMembers) object).getName()+ " -- " + ((ClassMembers) object).getRelation());} else {childHolder.tvTitle.setText(((ClassMembers) object).getName());}} else if (object instanceof AccountInformation) {Glide.with(mContext).load(SocketService.FILE_UPLOAD_URL+((AccountInformation) object).getHeadPortrait()).error(mContext.getResources().getDrawable(R.drawable.group_member_icon_default)).into(childHolder.contactsPic);if (((AccountInformation) object).getRelation() != null&& ((AccountInformation) object).getRelation().trim().length() > 0) {childHolder.tvTitle.setText(((AccountInformation) object).getUserName()+ " -- " + ((AccountInformation) object).getRelation());} else {childHolder.tvTitle.setText(((AccountInformation) object).getUserName());}}}return convertView;}//大组成员private static class ViewHolderGroup {TextView group_name_tv;ImageView open_close_group_IM;}//小组成员final static class ViewHolderChild {TextView tvLetter;CircleImageView contactsPic;TextView tvTitle;ImageButton sendShortMessageIB;ImageButton phoneIB;}//小组成员里面的button@Overridepublic void onClick(View v) {// TODO Auto-generated method stubint position = 0;switch (v.getId()) {case R.id.send_short_message_IB:position = (int)v.getTag(R.id.send_short_message_IB);LogUtil.i(Tag, "wdh 位置 sendShortMessageIB" +v.getTag(R.id.send_short_message_IB)); Object object = mGroupMemberList.get(mGroupPosition).get(position);Uri uri = null;if (object instanceof ClassMembers) {uri =Uri.parse("smsto:" + ((ClassMembers)object).getPhone());}else if (object instanceof AccountInformation) {uri =Uri.parse("smsto:" + ((AccountInformation)object).getPhoneNum());}if (null != uri) {Intent shortMessageIntent = new Intent(Intent.ACTION_VIEW, uri);mContext.startActivity(shortMessageIntent); }break;case R.id.phone_IB:LogUtil.i(Tag, "wdh 位置 phoneIB" + v.getTag(R.id.phone_IB));position = (int)v.getTag(R.id.phone_IB); Object phoneObject = mGroupMemberList.get(mGroupPosition).get(position);Intent callIntent = null;if (phoneObject instanceof ClassMembers) {callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" +((ClassMembers)phoneObject).getPhone()));}else if (phoneObject instanceof AccountInformation) {callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" +((AccountInformation)phoneObject).getPhoneNum()));}if (null != callIntent) {mContext.startActivity(callIntent);}break;default:break;}}}
3,fragment布局fragment_contacts_expandablelistview.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:background="@color/white"><ExpandableListViewandroid:id="@+id/group_expandableListView"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_gravity="center"android:dividerHeight="1dp"android:divider="#E0E0E0" /></LinearLayout>
4,这个是大的分组的布局expandableliseview_grorp_item.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="40dp"android:gravity="center_vertical" ><ImageViewandroid:id="@+id/open_close_group_IM" android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_marginLeft="13dp"android:layout_alignParentLeft="true"android:layout_centerVertical="true"/><TextView android:id="@+id/group_name_TV"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@+id/open_close_group_IM"android:layout_marginLeft="12dp"android:textSize="15sp"android:layout_centerVertical="true"android:textColor="#333333"/></RelativeLayout>
5,小的分组的布局,就是item布局item_class_member.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="47dp"android:gravity="center_vertical"android:descendantFocusability="blocksDescendants"android:orientation="vertical" ><TextViewandroid:id="@+id/catalog"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#E0E0E0"android:textColor="#999999"android:layout_weight="1.0"android:paddingLeft="5dip"android:paddingTop="5dip"android:paddingBottom="5dip"android:text="@string/camera_shooting"/><LinearLayout android:layout_width="match_parent"android:layout_height="57dp"android:orientation="horizontal"android:gravity="center_vertical"><com.dami.student.ui.chatui.widget.CircleImageViewandroid:id="@+id/contactsPic"android:layout_width="41dp"android:layout_height="41dp"android:layout_marginLeft="4dp"android:layout_weight="1"></com.dami.student.ui.chatui.widget.CircleImageView><TextViewandroid:id="@+id/title"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_vertical"android:textColor="#333333"android:layout_weight="6"android:textSize="15sp"android:text="@string/hold_to_talk"/><ImageButton android:id="@+id/send_short_message_IB"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="4dp"android:focusable="false"android:clickable="true"android:scaleType="fitXY"android:background="@drawable/send_short_message"/><ImageView android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="0.5"/><ImageButton android:id="@+id/phone_IB"android:layout_width="wrap_content"android:layout_height="wrap_content"android:focusable="false"android:clickable="true"android:scaleType="fitXY"android:background="@drawable/phone"/><ImageView android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"/></LinearLayout ></LinearLayout>
参考文章:https://www.aliyun.com/jiaocheng/111569.html
https://blog.csdn.net/xyzz609/article/details/51975416
https://blog.csdn.net/way_ping_li/article/details/7995552