ExpandableListView是ListView的子类,它扩展了ListView,对列表项实现了item分组,它的列表项由ExpandableListAdapter提供。ExpandableListAdapter是一个接口,实现该接口的是一个抽象类BaseExpandableListAdapter。
1、目标 通过ExpandableListView和自定义的ExpandableListAdapter实现主流APP上复杂功能的列表。
2、最终实现效果图
3、实现
3.1、布局.xml 主布局只需要一个<ExpandableListView>视图即可。
3.2、实现自定义ExpandableListAdapter 需要继承BaseExpandableListAdapter并实现所有的抽象方法。
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<Item> mData;
public MyExpandableListAdapter(Context context, List<Item> mData){
this.context = context;
this.mData = mData;
}
@Override
public int getGroupCount() {
return mData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return mData.get(groupPosition).sonText.length;
}
@Override
public Object getGroup(int groupPosition) {
return mData.get(groupPosition).groupText;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mData.get(groupPosition).sonText[childPosition];
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
LinearLayout ll;
ViewHolder vh;
if (convertView == null){
ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
ImageView imv = new ImageView(context);
ViewGroup.LayoutParams lp1 = new ViewGroup.LayoutParams(250, 250);
imv.setLayoutParams(lp1);
imv.setPadding(100, 0, 0, 0);
ll.addView(imv);
TextView tv = new TextView(context);
tv.setPadding(40, 0, 0, 0);
ViewGroup.LayoutParams lp2 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
tv.setLayoutParams(lp2);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setTextSize(20f);
ll.addView(tv);
vh = new ViewHolder(imv, tv);
ll.setTag(vh);
} else {
ll = (LinearLayout) convertView;
vh = (ViewHolder) ll.getTag();
}
vh.imv.setImageResource(mData.get(groupPosition).imgId);
vh.tv.setText(getGroup(groupPosition).toString());
return ll;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
TextView tv;
if (convertView == null){
tv = new TextView(context);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(lp);
tv.setGravity(Gravity.CENTER);
tv.setTextSize(18f);
}else{
tv = (TextView) convertView;
}
tv.setText(getChild(groupPosition, childPosition).toString());
return tv;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
class ViewHolder{
ImageView imv;
TextView tv;
public ViewHolder(ImageView imv, TextView tv) {
this.imv = imv;
this.tv = tv;
}
}
相关重写方法功能介绍:
public int getGroupCount():返回分组item个数
public int getChildrenCount(int groupPosition):返回特定分组中子item的个数
public Object getGroup(int groupPosition):返回特定分组item
public Object getChild(int groupPosition, int childPosition): 返回特定分组中特定位置的子item
itempublic long getGroupId(int groupPosition): 返回分组item的ID
public long getChildId(int groupPosition, int childPosition):返回特定分组中特定位置的子item ID
public boolean hasStableIds():表示分组和子选项是否持有稳定的id。返回false,通过getxxxId来判断哪些需要getxxxView从而达到局部刷新的效果,在getxxxView比较耗时的情况下起到优化的效果。
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent):是一个最重要方法。获得父列表项视图。convertView参数:Android中的常用Adapter都会涉及到convertView的使用,使用convertView主要是为了缓存视图View,用以增加ListView的item View加载效率。在Adapter的getxxxView中,先判断convertView是否为空null,如果非空,则直接对convertView复用,否则才创建新的View。ViewHolder类是视图组件的持有者,把布局中相关的组件都封装起来,以便使用。setTag()和getTag()是把ViewHolder对象和布局关联起来,可以理解为为ViewHolder对象打了一个标签,使它属于相应的布局。因为不同布局使用的ViewHolder可能不同。
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent):参照上面,返回子item的视图。
public boolean isChildSelectable(int groupPosition, int childPosition):子item是否可点击。
3.3、封装数据类
public class Item {
int imgId;
String groupText;
String[] sonText;
public Item(int imgId, String groupText, String[] sonText) {
this.imgId = imgId;
this.groupText = groupText;
this.sonText = sonText;
}
}
3.4、MainActivity
public class MainActivity extends AppCompatActivity {
public int[] imgs = new int[] {R.drawable.book, R.drawable.clothes, R.drawable.foot, R.drawable.movie};
public String[] gt = new String[]{"收藏书架", "时尚服装", "美味小吃", "热映电影"};
public String[][] items = new String[][] {
new String[]{"狭义相对论", "时间简史", "鲁滨逊漂流记", "安徒生童话", "琼美卡随想录"},
new String[]{"羊毛衫", "复古牛仔", "真丝旗袍", "中长款羊毛大衣"},
new String[]{"驴肉火烧", "真香烤鸭", "三只松鼠", "梭哈辣条", "薯片", "娃哈哈饮品"},
new String[]{"封神榜", "前任3", "流浪地球", "悬崖之上", "复仇者联盟", "金刚大战哥斯拉"}
};
private ExpandableListView elv;
private MyExpandableListAdapter mela;
public List<Item> data = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
elv = findViewById(R.id.elv);
for (int i = 0; i < imgs.length; i++) {
Item it = new Item(imgs[i], gt[i], items[i]);
data.add(it);
}
mela = new MyExpandableListAdapter(this, data);
elv.setAdapter(mela);
}
}