1. 简介
看下源码中的英文介绍
/**
* A view that shows items in a vertically scrolling two-level list. This
* differs from the {@link ListView} by allowing two levels: groups which can
* individually be expanded to show its children. The items come from the
* {@link ExpandableListAdapter} associated with this view.
*
* Expandable lists are able to show an indicator beside each item to display
* the item’s current state (the states are usually one of expanded group,
* collapsed group, child, or last child). Use
* {@link #setChildIndicator(Drawable)} or {@link #setGroupIndicator(Drawable)}
* (or the corresponding XML attributes) to set these indicators (see the docs
* for each method to see additional state that each Drawable can have). The
* default style for an {@link ExpandableListView} provides indicators which
* will be shown next to Views given to the {@link ExpandableListView}. The
* layouts android.R.layout.simple_expandable_list_item_1 and
* android.R.layout.simple_expandable_list_item_2 (which should be used with
* {@link SimpleCursorTreeAdapter}) contain the preferred position information
* for indicators.
*
* The context menu information set by an {@link ExpandableListView} will be a
* {@link ExpandableListContextMenuInfo} object with
* {@link ExpandableListContextMenuInfo#packedPosition} being a packed position
* that can be used with {@link #getPackedPositionType(long)} and the other
* similar methods.
*
* Note: You cannot use the valuewrap_content
* for theandroid:layout_height
attribute of a
* ExpandableListView in XML if the parent’s size is also not strictly specified
* (for example, if the parent were ScrollView you could not specify
* wrap_content since it also can be any length. However, you can use
* wrap_content if the ExpandableListView parent has a specific size, such as
* 100 pixels.
*
* @attr ref android.R.styleable#ExpandableListView_groupIndicator
* @attr ref android.R.styleable#ExpandableListView_indicatorLeft
* @attr ref android.R.styleable#ExpandableListView_indicatorRight
* @attr ref android.R.styleable#ExpandableListView_childIndicator
* @attr ref android.R.styleable#ExpandableListView_childIndicatorLeft
* @attr ref android.R.styleable#ExpandableListView_childIndicatorRight
* @attr ref android.R.styleable#ExpandableListView_childDivider
* @attr ref android.R.styleable#ExpandableListView_indicatorStart
* @attr ref android.R.styleable#ExpandableListView_indicatorEnd
* @attr ref android.R.styleable#ExpandableListView_childIndicatorStart
* @attr ref android.R.styleable#ExpandableListView_childIndicatorEnd
*/
ExpandableListView是不同于ListView的两级列表View,可以收起可以展开。通过ExpandableListAdapter来配置需要现实的items。
2. 基本使用
2.1 布局文件
group.xml(一级节点item布局)
<?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="30dp"
android:orientation="vertical" >
<TextView
android:id="@+id/group_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:text=""
/>
</LinearLayout>
child.xml(二级节点item)
<?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="horizontal"
android:paddingLeft="40dp">
<TextView
android:id="@+id/textOne"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="" />
</LinearLayout>
actiivty_main.xml(主界面布局)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context="cn.onlyloveyd.expandablelistviewdemo.MainActivity">
<ExpandableListView
android:id="@+id/expandable_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="@drawable/expand"
android:childIndicator="@drawable/collapse"
/>
</LinearLayout>
2.2 代码
YEAdapter.java(可伸展列表对应的Adapter)
public class YEAdapter extends BaseExpandableListAdapter {
//一级节点数据
private List<GroupItem> mGroupItems;
private Context mContext;
public YEAdapter(Context context, List<GroupItem> mData) {
mGroupItems = mData;
mContext = context;
}
/**
* 一级节点数量
* @return
*/
@Override
public int getGroupCount() {
return mGroupItems.size();
}
/**
* 指定位置一级节点下二级节点数量
* @param groupPosition
* @return
*/
@Override
public int getChildrenCount(int groupPosition) {
return mGroupItems.get(groupPosition).mChildList.size();
}
/**
* 获取一级节点对象
* @param groupPosition
* @return
*/
@Override
public Object getGroup(int groupPosition) {
return mGroupItems.get(groupPosition);
}
/**
* 获取二级节点对象
* @param groupPosition
* @param childPosition
* @return
*/
@Override
public Object getChild(int groupPosition, int childPosition) {
return mGroupItems.get(groupPosition).mChildList.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;
}
/**
* ID是否稳定
* @return
*/
@Override
public boolean hasStableIds() {
return true;
}
/**
* 获取一级节点view
* @param groupPosition
* @param isExpanded
* @param convertView
* @param parent
* @return
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View view=null;
TextView mTv;
if(convertView!=null){
view = convertView;
mTv = (TextView) view.getTag();
}else{
view = View.inflate(mContext,R.layout.group, null);
mTv = (TextView) view.findViewById(R.id.group_text);
view.setTag(mTv);
}
mTv.setText(mGroupItems.get(groupPosition).title);
return view;
}
/**
* 获取二级节点View
* @param groupPosition
* @param childPosition
* @param isLastChild
* @param convertView
* @param parent
* @return
*/
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View view=null;
TextView mTextView;
if(convertView!=null){
view = convertView;
mTextView = (TextView) view.getTag();
}else{
view = View.inflate(mContext,R.layout.child, null);
mTextView = (TextView) view.findViewById(R.id.textOne);
view.setTag(mTextView);
}
mTextView.setText(mGroupItems.get(groupPosition).mChildList.get(childPosition).message);
return view;
}
/**
* 二级菜单是否可选(true为可选,false为不可选,也就是响应和不响应点击事件)
* @param groupPosition
* @param childPosition
* @return
*/
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
/**
* 一级节点对象
*/
public static class GroupItem {
String title;
List<ChildItem> mChildList;
}
/**
* 二级节点对象
*/
public static class ChildItem {
String message;
}
}
具体解释请查阅注释信息
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<YEAdapter.GroupItem> mGroupItems = new ArrayList<>();
for (int i = 0; i < 5; i++) {
YEAdapter.GroupItem item = new YEAdapter.GroupItem();
item.title = "this is " + i + "nd group item";
List<YEAdapter.ChildItem> mChildItems = new ArrayList<>();
for (int j = 0; j < 4; j++) {
YEAdapter.ChildItem item1 = new YEAdapter.ChildItem();
item1.message = "this is " + i + "nd group item's " + j + "nd child";
mChildItems.add(item1);
}
item.mChildList = mChildItems;
mGroupItems.add(item);
}
ExpandableListView expandableListView = (ExpandableListView) this.findViewById(R.id.expandable_list);
YEAdapter yeAdapter = new YEAdapter(this, mGroupItems);
expandableListView.setAdapter(yeAdapter);
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Toast.makeText(MainActivity.this, groupPosition + "nd group's " + childPosition + "nd Item is clicked!", Toast.LENGTH_SHORT).show();
return false;
}
});
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Toast.makeText(MainActivity.this, groupPosition + "nd group is clicked", Toast.LENGTH_SHORT).show();
return false;
}
});
expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(MainActivity.this, "the " + groupPosition + "nd group is collapsed", Toast.LENGTH_SHORT).show();
}
});
expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(MainActivity.this, "the " + groupPosition + "nd group is expanded", Toast.LENGTH_SHORT).show();
}
});
}
}
2.3 实际效果
3. 类结构
3.1 属性值
属性值 | 含义 |
---|---|
groupIndicator | 一级节点指示器 |
indicatorLeft | 一级节点指示器距离左边界距离 |
indicatorRight | 一级节点指示器距离右边界距离 |
childIndicator | 意义同group中相同 |
childIndicatorLeft | 意义同group中相同 |
childIndicatorRight | 意义同group中相同 |
childDivider | 设置二级节点的分割想,颜色或者drawable |
indicatorStart | 同indicatorLeft |
indicatorEnd | 同indicatorRight |
childIndiatorStart | 同childIndicatorLeft |
childIndicatorEnd | 同childIndicatorRight |
主要看看分割线效果
设置图片
divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="@color/colorAccent"/>
<corners
android:radius="3dp"/>
</shape>
设置颜色
android:childDivider=”@color/colorPrimary”
那么一级节点如何设置分割线?
看这个例子
android:childDivider="@color/colorPrimary"
android:divider="@drawable/divider"
android:dividerHeight="2dp"
给一级菜单和二级菜单设置不同的分割线,看下效果
二级节点依然显示的时我们设置的分割线,但是当一级节点展开时,展开的节点的一级分割线变成了二级节点的分割线样式,收起后恢复成一级节点的分割线样式。
3.2 常用方法
具体内容请查阅源码。
4. 设置上下文菜单
4.1 expandable_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/menu_item1"
android:title="菜单项1">
</item>
<item
android:id="@+id/menu_item2"
android:title="菜单项2">
</item>
</menu>
4.2 onCreateContextMenu
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("expandable menu");
getMenuInflater().inflate(R.menu.expandable_menu, menu);
}
4.3 onContextItemSelected
@Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
super.onContextItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_item1:
Toast.makeText(this, "this is first menu item", Toast.LENGTH_SHORT).show();
break;
case R.id.menu_item2:
Toast.makeText(this, "this is second menu item", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return super.onContextItemSelected(item);
}
4.4 item长按事件显示菜单并注册上下文菜单
expandableListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD)
{
expandableListView.showContextMenu();
return true;
}
return false;
}
});
registerForContextMenu(expandableListView);