今天想和大家分享的是QQ好友列表的实现,我们知道,在默认情况下,QQ好友列表是处于收缩状态的,此时,列表显示好友分组名称。当我们单击分组时,列表处于展开状态,列表显示该分组下的项目。当再次单击分组时,列表恢复到收缩状态。
首先想和大家说说实现QQ好友列表的原理,我们给每个ListView的项目中嵌套一个ListView,默认情况下嵌套的ListView(子控件)是隐藏的,当单击ListView(父控件)时,嵌套的ListView(子控件)将显示出来,并显示该分组下的项目。
接下来我们我们定义几个主要的类:Group、GroupItem、GroupItemAdapter、FriendViewAdapter。其中,Group类用于描述好友分组结构、GroupItem类用于描述好友结果、GroupItemAdapter是好友的数据适配器、FriendViewAdapter是分组的数据适配器,下面我们来分别讲述它们。
1、Group类封装了分组的标题和分组内的数据,定义如下:
package com.android.Mobile.QQ.FriendsView; import java.util.List; public class Group { //分组名称 private String mGroupName; //分组项目 private List<GroupItem> mGroupItems; public Group(String GroupName,List<GroupItem> GroupItems) { this.mGroupName=GroupName; this.mGroupItems=GroupItems; } public String getGroupName() { return mGroupName; } public void setGroupName(String mGroupName) { this.mGroupName = mGroupName; } public List<GroupItem> getGroupItems() { return mGroupItems; } public void setGroupItems(List<GroupItem> mItems) { this.mGroupItems = mItems; } }
2、GroupItem类用于描述分组内的项目,定义如下:
package com.android.Mobile.QQ.FriendsView; public class GroupItem { private String Title; private String Content; public GroupItem(String mTitle,String mContent) { this.Title=mTitle; this.Content=mContent; } public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } }
3、GroupItemAdapter适配器类:
package com.android.Mobile.QQ.FriendsView; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class GroupItemAdapter extends BaseAdapter { private Context mContext; private List<GroupItem> mItems; public GroupItemAdapter(Context mContext,List<GroupItem> mItems) { this.mContext=mContext; this.mItems=mItems; } @Override public int getCount() { return mItems.size(); } @Override public Object getItem(int Index) { return mItems.get(Index); } @Override public long getItemId(int Index) { return Index; } @Override public View getView(int Index, View mView, ViewGroup mParent) { mView=LayoutInflater.from(mContext).inflate(R.layout.layout_group_item, null); //绑定好友结构中的Title ((TextView)mView.findViewById(R.id.Group_Item_Title)).setText(mItems.get(Index).getTitle()); //绑定好友结构中的Content ((TextView)mView.findViewById(R.id.Group_Item_Content)).setText(mItems.get(Index).getContent()); return mView; } }
4、主适配器类FriendViewAdapter
package com.android.Mobile.QQ.FriendsView; 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.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; public class FriendViewAdapter extends BaseAdapter { private Context mContext; private List<Group> mGroups; private boolean isShowGroupItem=false; public FriendViewAdapter(Context mContext,List<Group> mGroups) { this.mContext=mContext; this.mGroups=mGroups; } @Override public int getCount() { return mGroups.size(); } @Override public Object getItem(int Index) { return mGroups.get(Index); } @Override public long getItemId(int Index) { return Index; } @Override public View getView(final int Index, View mView, ViewGroup mParent) { mView=LayoutInflater.from(mContext).inflate(R.layout.layout_group, null); //设置分组的名称 ((TextView)mView.findViewById(R.id.Group_GroupName)).setText(mGroups.get(Index).getGroupName()); //设置分组容量 String mItemsCount=String.valueOf(mGroups.get(Index).getGroupItems().size()); ((TextView)mView.findViewById(R.id.Group_ItemCount)).setText(mItemsCount); //设置分组下的列表 final ListView ItemsList=(ListView)mView.findViewById(R.id.GroupItemList); GroupItemAdapter mAdapter=new GroupItemAdapter(mContext, mGroups.get(Index).getGroupItems()); ItemsList.setAdapter(mAdapter); ItemsList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapter, View view, int index,long id) { Toast.makeText(mContext, "Item "+index+" Click!", Toast.LENGTH_LONG).show(); } }); //设置分组小的列表高度 setGroupHeight(ItemsList); //给分组添加Click事件 final RelativeLayout GroupLayout=(RelativeLayout)mView.findViewById(R.id.GroupLayout); GroupLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(!isShowGroupItem) { ItemsList.setVisibility(View.VISIBLE); GroupLayout.setBackgroundResource(R.drawable.group_bg_open); isShowGroupItem=true; } else { ItemsList.setVisibility(View.GONE); GroupLayout.setBackgroundResource(R.drawable.grop_bg_close); isShowGroupItem=false; } } }); return mView; } /* * 这是一个神奇的方法,在所有的View嵌套问题中都需要解决这个问题 */ private void setGroupHeight(ListView mListView) { int mTotalHeight=0; ListAdapter mAdapter=mListView.getAdapter(); for(int i=0;i<mAdapter.getCount();i++) { View ItemView=mAdapter.getView(i, null, mListView); ItemView.measure(0, 0); mTotalHeight+=ItemView.getMeasuredHeight(); } ViewGroup.LayoutParams mParams=mListView.getLayoutParams(); mParams.height=mTotalHeight; mListView.setMinimumHeight(mTotalHeight); } }
程序运行效果:
两点总结:
1、自定义ListView无法响应OnItemClick事件的解决方案是将自定义布局的根节点属性android:descendantFocusability设置为blocksDescendants,这样嵌套的子控件可以取得焦点,响应响应的操作。
2、嵌套子控件时,需要使用下面的方法根据子控件的内容重新设置父控件的高度,否则子控件会出现显示不全的问题:
/* * 这是一个神奇的方法,在所有的View嵌套问题中都需要解决这个问题 */ private void setGroupHeight(ListView mListView) { int mTotalHeight=0; ListAdapter mAdapter=mListView.getAdapter(); for(int i=0;i<mAdapter.getCount();i++) { View ItemView=mAdapter.getView(i, null, mListView); ItemView.measure(0, 0); mTotalHeight+=ItemView.getMeasuredHeight(); } ViewGroup.LayoutParams mParams=mListView.getLayoutParams(); mParams.height=mTotalHeight; mListView.setMinimumHeight(mTotalHeight); }