ExpandableListView基本使用(创建一个歌单二级列表),属性,适配器,指示器修改设置
效果图:
ExpandableListView基本属性介绍:
XML属性(来自官网) | 作用 |
---|---|
android:childIndicator |
子项的指示器 |
android:childDivider |
为子项设置分割线(Drawable/Color ),默认大概是1dp |
android:childIndicatorEnd |
类比属性childIndicatorStart |
android:childIndicatorLeft |
类比属性childIndicatorStart |
android:childIndicatorRight |
类比属性childIndicatorStart |
android:childIndicatorStart |
箭头或者自己设置的图片的左边框距离手机左边边缘的距离,类似于marginLeft |
android:groupIndicator |
设置gruop 的小箭头,不要的话设为@null |
android:indicatorEnd |
|
android:indicatorLeft |
箭头或者自己设置的图片的右边框距离手机左边边缘的距离,类似于marginLeft |
android:indicatorRight |
|
android:indicatorStart |
|
其他的是继承自View\ListView 等的属性 |
dividerHeight (间距)、 divider (分割线样式) |
使用ExpandableListView
详细步骤:
步骤Ⅰ:在需要二级列表的地方写上<ExpandableListView .... />
:
<ExpandableListView
android:id="@+id/elv_list"
android:layout_width="match_parent"
android:layout_height="500dp"
android:divider="@null"
android:groupIndicator="@null"
android:dividerHeight="2dp"/>
步骤Ⅱ:编写gruop
布局xml
文件(类似RecyclerView
需要编写item
布局一样):
layout_elv_group.xml
:
<?xml version="1.0" encoding="utf-8"?>
<!--ELV列表的父布局-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="43dp"
android:background="#222327"
android:elevation="2dp">
<TextView
android:id="@+id/group_name"
android:textColor="#a6a6a8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="默认歌单"
android:layout_marginTop="11dp"
android:layout_marginBottom="11dp"
android:layout_marginLeft="20dp"
android:textStyle="bold"
android:textSize="13sp"/>
<ImageView
android:id="@+id/img_open_or_close"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/group_name"
android:layout_marginLeft="10dp"
android:background="@drawable/icon_floder"/>
<ImageView
android:id="@+id/group_img_add"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@mipmap/icon_add_gedan"
android:layout_alignParentRight="true"
android:layout_marginRight="21dp"
android:layout_marginTop="11dp"/>
</RelativeLayout>
预览:
步骤Ⅲ:编写group
中的item
布局xml
文件:
layout_elv_group_item.xml
:
<?xml version="1.0" encoding="utf-8"?>
<!--子歌单布局-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_item"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@drawable/ripple_elv_item"
android:elevation="1dp">
<ImageView
android:id="@+id/elv_img_songlist"
android:layout_width="49dp"
android:layout_height="49dp"
android:layout_marginLeft="20dp"
android:background="@drawable/bac"
android:layout_centerVertical="true"/>
<TextView
android:id="@+id/elv_tv_songlist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/elv_img_songlist"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:text="迷失的风筝"
android:textSize="15sp"
android:textStyle="bold"
android:textColor="@color/vx_text_color"/>
<TextView
android:id="@+id/elv_tv_song_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="520首"
android:layout_below="@id/elv_tv_songlist"
android:layout_toRightOf="@id/elv_img_songlist"
android:layout_marginLeft="15dp"
android:textSize="13sp"
android:layout_marginTop="5dp"
android:textColor="@color/vx_text_color"/>
</RelativeLayout>
预览:
步骤Ⅳ:(★)编写自定义适配器ElvLoveAdapter
继承自BaseExpandableListAdapter
,并实现里面的方法(最重要的是重写getGroupView()
和getChildView()
方法):
/**
* <p>
* ExpandableListView适配器
* </p>
*/
public class ElvLoveAdapter extends BaseExpandableListAdapter {
private static final String TAG = "ElvLoveAdapter";
/**
* group的数据源
*/
private ArrayList<String> mGroup;
/**
* item的数据源,ElvItem是子项数据Bean
*/
private ArrayList<ArrayList<ElvItem>> mItemList;
private Context mContext;
private final LayoutInflater mInflater;
/**
* 构造器
*
* @param mGroup 父项列表
* @param mItemList 子项列表
* @param mContext 上下文
*/
public ElvLoveAdapter(ArrayList<String> mGroup, ArrayList<ArrayList<ElvItem>> mItemList, Context mContext, LayoutInflater mInflater) {
this.mGroup = mGroup;
this.mItemList = mItemList;
this.mContext = mContext;
this.mInflater = LayoutInflater.from(mContext);
}
/**
* 获取父项个数
*
* @return
*/
@Override
public int getGroupCount() {
return mGroup.size();
}
/**
* 获取某个父项的子项个数
*
* @param groupPosition
* @return
*/
@Override
public int getChildrenCount(int groupPosition) {
return mItemList.get(groupPosition).size();
}
/**
* 获取某个父项
*
* @param groupPosition
* @return
*/
@Override
public Object getGroup(int groupPosition) {
return mGroup.get(groupPosition);
}
/**
* 获取某个子项
*
* @param groupPosition
* @param childPosition
* @return
*/
@Override
public Object getChild(int groupPosition, int childPosition) {
return mItemList.get(groupPosition).get(childPosition);
}
/**
* 获取父项的Id
*
* @param groupPosition
* @return
*/
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
/**
* 获取子项的Id
*
* @param groupPosition
* @param childPosition
* @return
*/
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
/**
* 获取父项的View
*
* @param groupPosition group所在位置
* @param isExpanded group是否打开
* @param convertView 容器View
* @param parent 父布局
* @return
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupViewHolder groupViewHolder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.layout_elv_group, parent, false);
}
groupViewHolder = new GroupViewHolder(convertView);
// group的名字
String group = mGroup.get(groupPosition);
// 设置默认歌单的名字
groupViewHolder.groupName.setText(group);
// 判断group是否打开来设置指示器的方向
if(isExpanded){
groupViewHolder.indicator.setBackgroundResource(R.drawable.icon_open);
}else {
groupViewHolder.indicator.setBackgroundResource(R.drawable.icon_floder);
}
// 添加子歌单点击事件
groupViewHolder.addSongList.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO 处理添加子歌单
Toast.makeText(v.getContext(), "添加功能待做", Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
/**
* 获取子项的View
*
* @param groupPosition 所在group位置
* @param childPosition 在group中的位置
* @param isLastChild 是否为最后一个子项
* @param convertView 容器view
* @param parent 父布局
* @return
*/
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ItemViewHolder itemViewHolder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.layout_elv_group_item, parent, false);
}
// 歌单进入动画,动画文件在后面有
convertView.setAnimation(AnimationUtils.loadAnimation(mContext, R.anim.anim_rcv_item_1));
itemViewHolder = new ItemViewHolder(convertView);
// 拿到子项Bean
ElvItem itemBean = mItemList.get(groupPosition).get(childPosition);
// 歌单名
String songListName = itemBean.getSongListName();
// 歌单封面资源id
int imgRes = itemBean.getImgRes();
// 歌单包含歌曲数目
String songCount = itemBean.getSongCount();
// 设置歌单封面
itemViewHolder.listCover.setImageResource(imgRes);
// 设置歌单名
itemViewHolder.songListName.setText(songListName);
// 设置歌单包含歌曲数目
itemViewHolder.songCount.setText(songCount);
// 添加子项点击时的水波纹效果,已经在设给布局的background属性了
//itemViewHolder.rl_item.setBackgroundResource(R.drawable.ripple_elv_item);
// 点击事件:跳转到对应歌单的详细页面
itemViewHolder.rl_item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "在[" + groupPosition + "]组中的第[" + childPosition + "]子项", Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
/**
* 子项是否被选中,如果要为子项设置点击事件需要返回true
*
* @param groupPosition
* @param childPosition
* @return
*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
/**
* 父项的view搭载器
*/
static class GroupViewHolder {
private TextView groupName;
private ImageView addSongList, indicator;
public GroupViewHolder(View view) {
groupName = view.findViewById(R.id.group_name);
addSongList = view.findViewById(R.id.group_img_add);
indicator = view.findViewById(R.id.img_open_or_close);
}
}
/**
* 子项的搭载器
*/
static class ItemViewHolder {
// 布局
private RelativeLayout rl_item;
// 歌单名,歌单包含的歌曲数目
private TextView songListName;
private TextView songCount;
// 歌单的封面
private ImageView listCover;
public ItemViewHolder(View view) {
songListName = view.findViewById(R.id.elv_tv_songlist);
songCount = view.findViewById(R.id.elv_tv_song_count);
listCover = view.findViewById(R.id.elv_img_songlist);
rl_item = view.findViewById(R.id.rl_item);
}
}
}
ElvItem.java
/**
* 二级列表 ExpandableListView 中 group 的子项的Bean类
*/
public class ElvItem {
// 封面图片资源id
private int mImgRes;
// 歌单名字
private String mSongListName;
// 包含歌曲的数目
private String mSongCount;
public ElvItem(){
}
public ElvItem(int mImgRes, String mSongListName, String mSongCount) {
this.mImgRes = mImgRes;
this.mSongListName = mSongListName;
this.mSongCount = mSongCount;
}
public int getImgRes() {
return mImgRes;
}
public void setImgRes(int mImgRes) {
this.mImgRes = mImgRes;
}
public String getSongListName() {
return mSongListName;
}
public void setSongListName(String mSongListName) {
this.mSongListName = mSongListName;
}
public String getSongCount() {
return mSongCount;
}
public void setSongCount(String mSongCount) {
this.mSongCount = mSongCount;
}
}
步骤Ⅴ:创建ExpandableListView
、适配器实例,初始化数据源,显示出来:
public class FavoriteFragment extends BaseFragment{
private ExpandableListView mExpandableListView;
private ElvLoveAdapter mAdapter;
private LayoutInflater mInflater;
private ArrayList<String> mGroupList = new ArrayList<>();
private ArrayList<ArrayList<ElvItem>> mItemList = new ArrayList<>();
public FavoriteFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_favorite, container, false);
init(view);
initData();
return view;
}
@Override
public void init(View view) {
mExpandableListView = view.findViewById(R.id.elv_list);
mAdapter= new ElvLoveAdapter(mGroupList, mItemList, view.getContext(), mInflater);
mExpandableListView.setAdapter(mAdapter);
// 这里去掉group点击时的水波纹,将其设置成透明
mExpandableListView.setSelector(new ColorDrawable(Color.TRANSPARENT));
}
public void initData(){
// 添加group数据
mGroupList.add("默认歌单");
// 添加子项数据
ArrayList<ElvItem> items = new ArrayList<>();
items.add(new ElvItem(R.drawable.img_1, "人生若只如初见", "10首"));
items.add(new ElvItem(R.drawable.img_2, "一枝红杏出墙来", "1024首"));
items.add(new ElvItem(R.drawable.img_3, "落霞与孤鹜齐飞", "521首"));
items.add(new ElvItem(R.drawable.img_4, "游戏战歌", "66首"));
mItemList.add(items);
}
}
去掉ExpandableListView
点击group
时的水波纹效果:
// 设置为透明,或者资源id
mExpandableListView.setSelector(new ColorDrawable(Color.TRANSPARENT));
去掉ExpandableListView
默认的箭头(可以自定义直接属性赋予资源id[不推荐]):
代码设置:
settingLists.setGroupIndicator(null);
直接属性设置:
<ExpandableListView
android:groupIndicator="@null"
/>
去掉ExpandableListView
的分割线:
<ExpandableListView
android:divider="@null"
/>
设置ExpandableListView
子项之间的间距:
<ExpandableListView
android:dividerHeight="8dp"
/>
设置ExpandableListView
默认是展开的:
// 需要先实例化ExpandabListView,数据源不为null,不然会报错
mExpandableListView.setAdapter(adapter);
// 获取group数目并遍历,设为默认展开
int groupCount = exListView.getCount();
for (inti=0; i<groupCount; i++) {
mExpandableListView.expandGroup(i);
};
判断group
是否被打开:
// groupPosition:gruop的位置
expandableListView.isGroupExpanded(groupPosition)
关闭group
:
// groupPosition:gruop的位置
expandableListView.collapseGroup(groupPosition);
group
的点击事件setOnGroupClickListener(OnGroupClickListener listener)
:
mExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
return false;
}
});
设置group
里的item
进入动画:
在适配器中的getChildView
()方法里面设置:
// 使用layoutAniamtion动画会报错
convertView.setAnimation(AnimationUtils.loadAnimation(mContext, R.anim.anim_rcv_item_1));
用到的动画资源anim_rcv_item_1.xml
:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true"
>
<!-- 先上升自身的20%的高度,然后再降下来-->
<translate
android:fromYDelta="-20%"
android:toYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<!-- 可见度0-1-->
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<!-- 先在XY放大到105%,再还原-->
<scale
android:fromXScale="105%"
android:toXScale="100%"
android:fromYScale="105%"
android:toYScale="100%"
android:pivotY="50%"
android:pivotX="50%"
android:interpolator="@android:anim/decelerate_interpolator"
/>
</set>