expandableListView 自定义样式以及scrollerView嵌套
来源:互联网 发布:夏一行 c语言 编辑:程序博客网 时间:2024/06/13 23:48
最近写项目需要用到ExpandableListView,由于第一次使用,被它各种虐。网上也查看很多资料,但都没有实质的对它做个总结。本人不才,把自己项目中遇到的问题小记一下,分享给初学者。(部分是网上copy的,敬请谅解)
ExpandableListView组件是android中一个比较常用的组件,当点击一个父item的时候可以将他的子item显示出来,像手机QQ中的好友列表就是实现的类型效果。
1、Expandablelistview的基本使用:
第一步:在main.xml中定义ExpandableListView(由于项目的需求要scrollerView嵌套ExpandableListView所以这里引用的事自定义的)
<com.demo.widget.ScrollDisabledExpandableListView
android:id="@+id/yuncomputer_screen_id_expandablelist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/yuncomputer_screen_id_tips"
android:dividerHeight="1dp"
android:childDivider="#e3e3e3"
android:divider="#e3e3e3"
android:listSelector="@color/no_color" />
注:如果要定义分割线的颜色,divider属性要直接写颜色值,要不然会不显示
第二步:定义group.xml
<TextView android:id="@+id/group_id_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="@color/black"
android:textSize="17sp"
android:paddingLeft="10dp"
/>
注:由于我要自定义箭头而且要更改箭头位置所以这里多了个imageView。
第三步:定义chilid.xml
<TextView android:id="@+id/child_id_pkg_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="17sp"
/>
第四步:重头戏,适配BaseExpandableListAdapter
public class MyAdapter extends BaseExpandableListAdapter {
List<String> groups;
Map<String, List<String>> packages;
Context context;
public YunPackageAdapter(Context context,List<String> groups,Map<String, List<String>> packages){
super();
this.context = context;
this.groups = groups;
this.packages = packages;
}
/**
* 获取父item的个数
*/
@Override
public int getGroupCount() {
// TODO Auto-generated method stub
return groups.size();
}
/**
* 获取当前父item下的子item的个数
*/
@Override
public int getChildrenCount(int groupPosition) {
// TODO Auto-generated method stub
String strKey = groups.get(groupPosition);
return packages.get(strKey).size();
}
/**
* 获取当前父item的数据
*/
@Override
public Object getGroup(int groupPosition) {
// TODO Auto-generated method stub
return groups.get(groupPosition);
}
/**
* 得到子item需要关联的数据
*/
@Override
public Object getChild(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
String strKey = groups.get(groupPosition);
return packages.get(strKey).get(childPosition);
}
/**
* 获取父item的ID
*/
@Override
public long getGroupId(int groupPosition) {
// TODO Auto-generated method stub
return groupPosition;
}
/**
* 获取子item的ID
*/
@Override
public long getChildId(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return childPosition;
}
@Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return true;
}
/**
* 设置父item组件(这里是自定义的箭头)
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
convertView = LayoutInflater.from(context).inflate(R.layout.group, null);
ImageView imgIndicator = (ImageView) convertView.findViewById(R.id.group_id_indicator);
TextView tvName = (TextView) convertView.findViewById(R.id.group_id_name);
tvName.setText(groups.get(groupPosition));
//key值必须为资源ID
convertView.setTag(R.layout.item_yuncomputer_group, groupPosition);
convertView.setTag(R.layout.item_yuncomputer_child,-1);//设置-1表示长按时点击的是父项。
return convertView;
}
/**
* 设置item的组件
*/
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
convertView = LayoutInflater.from(context).inflate(R.layout.child, null);
TextView tvPackageName = (TextView) convertView.findViewById(R.id.child_id_name);
convertView.setTag(R.layout.item_yuncomputer_child,childPosition);
convertView.setTag(R.layout.item_yuncomputer_group, groupPosition);
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
// TODO Auto-generated method stub
return true;
}
}
2、自定义groupIndicator
a、直接给groupIndicator自定义图片,为了图片不变形,要.9图片。缺点:只能通过.9图片大致调整箭头的位置,indicatorLeft属性对于某些终端不起作用,具体为啥我也不清楚。
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/list_item_expand" android:state_expanded="true"/>
<item android:drawable="@drawable/list_item_collapse"></item>
</selector>
===================================================
<ExpandableListView
…
android:groupIndicator="@drawable/list_expand"
…
/>
b、网上零零碎碎很多方法,我认为的最简单有效的是:
在group中自定义箭头,这样样式、位置就能精准配置了:首先
在group的xml中加入:
<ImageView android:id="@+id/group_id_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:scaleType="fitCenter"
android:src="@drawable/yuncomputer_close"
/>
再者:android:groupIndicator="@null"必须设置为null要不然会出现重叠的箭头而且自定义的无效;
然后在adapter中的getGroupView方法中加入:
if(isExpanded){
imgIndicator.setImageResource(R.drawable.open);
}else{
imgIndicator.setImageResource(R.drawable.close);
}
大功告成,啦啦啦啦......
3、对ExpandableListView的item点击事件是OnChildClickListener: onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) 同时控制groupPosition和childPosition才能精确控制点击的是哪一个item。
4、对ExpandableListView的item的长按事件:(此处为转载:转载地址:http://blog.csdn.net/t5721654/article/details/6857357)
关于ExpandableListView长按事件处理,网上很多都是使用将上下文菜单注册到ExpandableListView上实现长按事件。
- /**
- * 长按邮箱快捷选项
- * @author King
- */
- private class QuickWayListener implements OnItemLongClickListener{
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int pos, long id) {
- int groupPos = (Integer)view.getTag(R.id.xxx01); //参数值是在setTag时使用的对应资源id号
- int childPos = (Integer)view.getTag(R.id.xxx02);
- if(childPos == -1){//长按的是父项
- //根据groupPos判断你长按的是哪个父项,做相应处理(弹框等)
- } else {
- //根据groupPos及childPos判断你长按的是哪个父项下的哪个子项,然后做相应处理。
- }
- return false;
- }
- }
下面来说我的解决方法,方法有点投机取巧。首先说明一点,使用我这种方法必须使用自定义的BaseExpandableListAdapter,至于为什么,具体后面讲到。
ExpandableListView本身有继承自AdapterView的setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener)方法。实现监听器:
- /**
- * 长按邮箱快捷选项
- * @author King
- */
- private class QuickWayListener implements OnItemLongClickListener{
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int pos, long id) {
- //pos不可用说明见下文
- return false;
- }
- }
如果这个方法是用在ListView长按事件中刚刚好,但在ExpandableListView中,第三个参数pos不能区分开点击的是父项还是子项,以及哪个父项或子项。
在ExpandableListView响应的onItemLongCkick方法中,pos参数值为:从上到下,父项+展现的子项到点击位置的数目(注意:是展现的,隐藏的子项不包括,从0开始)。
例如:
父项1(隐藏3个子项)
父项2
|—子项2-0
|—子项2-1
|—子项2-2
长按子项2-1时,pos值为3。显然根据pos值是无法确定点击的是哪个子项或父项的。
因此依赖pos是很难处理点击位置的。
如果可以直接在onItemLongClick方法中获取groupPos,及childPos该多好呢?
于是看到了onItemLongClick方法第二个参数:view。这里的view是你按中的位置对应的view。view有个方法getTag(int key)。如果在创建此view的时候就把groupPos,childPos通过setTag(int key, Object value)设置进去,在响应onItemLongClick不就可以直接拿出来用了么。
现在就要讲到必须使用自定义的BaseExpandableListAdapter的理由了。
要把groupPos,childPos通过setTag的方式绑定到view中,就必须操作该view的创建过程。要控制这个过程就必须要在自定义BaseExpandableListAdapter中重写getGroupView及getChildView方法进行操作。如下:
- public class AccountListAdapter extends BaseExpandableListAdapter {
- ...省略其他方法
- @Override
- public View getChildView(int groupPosition, int childPosition,
- boolean isLastChild, View convertView, ViewGroup parent) {
- //我这里仅通过自己写的mkChildView()方法创建TextView来显示文字,更复杂的可以通过LayoutInflater来填充一个view
- TextView childTv = mkChildView();
- // 标记位置
- // 必须使用资源Id当key(不是资源id会出现运行时异常),android本意应该是想用tag来保存资源id对应组件。
- // 将groupPosition,childPosition通过setTag保存,在onItemLongClick方法中就可以通过view参数直接拿到了!
- childTv.setTag(R.id.xxx01, groupPosition);
- childTv.setTag(R.id.xxx02, childPosition);
- return childTv;
- }
- @Override
- public View getGroupView(int groupPosition, boolean isExpanded,
- View convertView, ViewGroup parent) {
- TextView groupTv = mkGroupView();
- // 设置同getChildView一样
- groupTv.setTag(R.id.xxx01, groupPosition);
- groupTv.setTag(R.id.xxx02, -1); //设置-1表示长按时点击的是父项,到时好判断。
- groupTv.setText(groups[groupPosition]);
- return groupTv;
- }
- }
- /**
- * 长按邮箱快捷选项
- * @author King
- */
- private class QuickWayListener implements OnItemLongClickListener{
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int pos, long id) {
- int groupPos = (Integer)view.getTag(R.id.xxx01); //参数值是在setTag时使用的对应资源id号
- int childPos = (Integer)view.getTag(R.id.xxx02);
- if(childPos == -1){//长按的是父项
- //根据groupPos判断你长按的是哪个父项,做相应处理(弹框等)
- } else {
- //根据groupPos及childPos判断你长按的是哪个父项下的哪个子项,然后做相应处理。
- }
- return false;
- }
- }
这个部分为转载,亲测实在是好用得不得了(偷笑)。
5、scrollerView嵌套ExpandableListView:
a、重写ExpandableListView
public class CustomExpandableListView extends ExpandableListView {
public CustomExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
b、动态计算expandablelistview的高度,xxx_group.xml和xxx_child.xml的最外层要用linearlayout,反正relativelayout不行,不知道为什么
private void setListViewHeight(ExpandableListView listView) {
ListAdapter listAdapter = listView.getAdapter();
int totalHeight = 0;
int count = listAdapter.getCount();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
c、较为复杂
public class ViewGroupForListView extends LinearLayout implements View.OnClickListener {
private ListAdapter mAdapter = null;
private OnItemClickListener mListener = null;
public ViewGroupForListView(Context context) {
super(context);
}
public ViewGroupForListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.setOrientation(VERTICAL);
}
/**
* 绑定数据
*/
protected void bindData() {
int count = mAdapter.getCount();
for(int i = 0; i < count; i++) {
View v = mAdapter.getView(i, null, null);
v.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
v.setOnClickListener(this);
v.setId(i);
addView(v, i);
}
}
/**
* 设置adapter
* @param adapter
*/
public void setAdapter(ListAdapter adapter) {
mAdapter = adapter;
if(this.getChildCount() != 0) {
removeAllViews();
}
bindData();
}
/**
* 获取adapter
* @return
*/
public ListAdapter getAdapter() {
return mAdapter;
}
/**
* 绑定监听
* @param listener
*/
public void setOnItemClickListener(OnItemClickListener listener) {
this.mListener = listener;
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(mListener != null) {
mListener.onItemClick(v.getId(), mAdapter);
}
}
/**
* 监听接口
* @author Visual
*
*/
public interface OnItemClickListener {
public void onItemClick(int position, ListAdapter adapter);
}
- expandableListView 自定义样式以及scrollerView嵌套
- Android关于自定义ExpandableListView样式
- scrollerview嵌套listview问题解决
- 解决ListView嵌套在ScrollerView中显示不全以及滑动冲突的问题
- 自定义ExpandableListView以及实现其分页
- ExpandableListView的自定义布局以及注意事项
- ScrollerView嵌套listview.实现,listview滑动
- android scrollerview嵌套recycleview滑动卡顿
- scrollerview嵌套RecyclerView滑动迟钝问题
- ScrollerView
- scrollerview
- 自定义ExpandableListView
- 自定义ExpandableListView
- 自定义ExpandableListView
- Android ExpandableListView嵌套ListView
- ExpandableListView 嵌套gridView使用
- ScrollView嵌套 ExpandableListView
- ExpandableListView(listView嵌套)
- linux环境下gsoap调用过程中的超时设置
- MySQLdb模块用法
- 从枚举值获取对应的文本描述
- React Native-2.CSS布局属性之伸缩项目属性
- fast-serialization 使用
- expandableListView 自定义样式以及scrollerView嵌套
- Android ANR问题分析
- 蓝桥杯-基础题-序列排序
- lightoj 1396 - Palindromic Numbers (III)
- 关于windows系统的一些知识
- 到处Android安装程序的 apk
- iOS中SideMenu侧边栏的实现,简易速成
- 添加小米push详细流程记录
- ALLEGRO 问题累积