参考:blog_Lei 的 android自定义侧滑LisitView(包含编辑、删除)
三个xml。分别是页面、ExpandableListView的Group、ExpandableListView的item:
1、activity_travel_list_create.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_travel_list_create"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ac2121"
tools:context="com.foodie.mango.TravelListCreateActivity">
<MyUI.SlideExpandableListView
android:id="@+id/exlist_create"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:groupIndicator="@null"
android:childDivider="#00ffffff"/>
</RelativeLayout>
2、item_exlist_addnum_group.xml
<?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">
<TextView
android:id="@+id/tv_group_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:paddingLeft="23dp"
android:textSize="12sp"
android:textColor="#FFBBBBBB"/>
</LinearLayout>
3、item_exlist_addnum_item.xml
<?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="52dp"
android:layout_marginLeft="0dp"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rlTop"
android:layout_width="match_parent"
android:layout_marginLeft="0dp"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_marginLeft="15dp"
android:layout_centerVertical="true"
android:gravity="left|center_vertical"
android:textSize="14sp"
android:textColor="#FFFFFF" />
<ImageView
android:id="@+id/btMinus"
android:layout_toLeftOf="@+id/tvNum"
android:layout_marginLeft="0dp"
android:layout_width="44dp"
android:layout_height="match_parent"
android:background="#00000000"/>
<TextView
android:id="@+id/tvNum"
android:layout_toLeftOf="@+id/btAdd"
android:layout_width="44dp"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:gravity="center"
android:text="1"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:background="#00000000"/>
<ImageView
android:id="@+id/btAdd"
android:layout_width="44dp"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_alignParentRight="true"
android:background="#00000000"/>
</RelativeLayout>
</RelativeLayout>
<!--delete-->
<TextView
android:id="@+id/delete"
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="#FFC20E23"
android:gravity="center"
android:paddingLeft="20dp"
android:textColor="#FFFFFF"
android:paddingRight="20dp"
android:text="删除" />
</LinearLayout>
4、MyBaseExpandableListAdapter1.java
package HTTPUtil;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import com.foodie.mango.R;
import java.util.ArrayList;
import domain.ListItem;
import static com.foodie.mango.R.id.tvNum;
/**
* Created by peng on 2018/4/18.
*/
public class MyBaseExpandableListAdapter1 extends BaseExpandableListAdapter {
private ArrayList<String> gData;
private ArrayList<ArrayList<ListItem>> iData;
private Context mContext;
private OnClickListenerEditOrDelete onClickListenerEditOrDelete;
public MyBaseExpandableListAdapter1(ArrayList<String> gData, ArrayList<ArrayList<ListItem>> iData, Context mContext) {
this.gData = gData;
this.iData = iData;
this.mContext = mContext;
}
@Override
public int getGroupCount() {
return gData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return iData.get(groupPosition).size();
}
@Override
public String getGroup(int groupPosition) {
return gData.get(groupPosition);
}
@Override
public ListItem getChild(int groupPosition, int childPosition) {
return iData.get(groupPosition).get(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) {
MyBaseExpandableListAdapter1.ViewHolderGroup groupHolder;
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(
R.layout.item_exlist_addnum_group, parent, false);
groupHolder = new MyBaseExpandableListAdapter1.ViewHolderGroup();
groupHolder.tv_group_title = (TextView) convertView.findViewById(R.id.tv_group_title);
convertView.setTag(groupHolder);
}else{
groupHolder = (MyBaseExpandableListAdapter1.ViewHolderGroup) convertView.getTag();
}
groupHolder.tv_group_title.setText(gData.get(groupPosition));
return convertView;
}
//取得显示给定分组给定子位置的数据用的视图
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final ViewHolderItem itemHolder;
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(
R.layout.item_exlist_addnum_item, parent, false);
itemHolder = new MyBaseExpandableListAdapter1.ViewHolderItem();
itemHolder.tvName=(TextView)convertView.findViewById(R.id.tvName);
itemHolder.checkBox=(CheckBox) convertView.findViewById(R.id.imgLamp);
itemHolder.tvNum = (TextView)convertView.findViewById(R.id.tvNum);
itemHolder.btAdd = (ImageView) convertView.findViewById(R.id.btAdd);
itemHolder.btMinus = (ImageView) convertView.findViewById(R.id.btMinus);
itemHolder.tvDelete=(TextView)convertView.findViewById(R.id.delete);
convertView.setTag(itemHolder);//store up viewHolder
}else{
itemHolder = (MyBaseExpandableListAdapter1.ViewHolderItem) convertView.getTag();
}
itemHolder.btMinus.setImageResource(R.mipmap.icon_minus);
itemHolder.btAdd.setImageResource(R.mipmap.icon_add);
itemHolder.tvName.setText(iData.get(groupPosition).get(childPosition).getiName());
itemHolder.tvDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListenerEditOrDelete!=null){
onClickListenerEditOrDelete.OnClickListenerDelete(groupPosition,childPosition);
}
}
});
itemHolder.btAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String numStr = itemHolder.tvNum.getText().toString();
int Num = Integer.parseInt(numStr);
if ((numStr!=null)&&(numStr!="0")){
Num = Num + 1;
itemHolder.tvNum.setText(Num+"");
}
}
});
itemHolder.btMinus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String numStr = itemHolder.tvNum.getText().toString();
int Num = Integer.parseInt(numStr);
if ((numStr!=null)&&(Num>=1)){
Num = Num - 1;
itemHolder.tvNum.setText(Num+"");
}else{
itemHolder.tvNum.setText("0");
}
}
});
return convertView;
}
//设置子列表是否可选中
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
private static class ViewHolderGroup{
TextView tv_group_title;
}
private static class ViewHolderItem{
TextView tvName,tvDelete,tvNum;
CheckBox checkBox;
ImageView btMinus,btAdd;
}
public interface OnClickListenerEditOrDelete{
void OnClickListenerDelete(int groupPosition,int position);
}
public void setOnClickListenerEditOrDelete(OnClickListenerEditOrDelete onClickListenerEditOrDelete1){
this.onClickListenerEditOrDelete=onClickListenerEditOrDelete1;
}
}
5、TravelListCreateActivity.java
package com.foodie.mango;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ExpandableListView;
import android.widget.Toast;
import java.util.ArrayList;
import HTTPUtil.MyBaseExpandableListAdapter1;
import domain.ListItem;
public class TravelListCreateActivity extends AppCompatActivity{
private ArrayList<String> gData = new ArrayList<String>();
private ArrayList<ArrayList<ListItem>> iData = new ArrayList<ArrayList<ListItem>>();
private ArrayList<ListItem> lData = new ArrayList<ListItem>();
private Context mContext;
private ExpandableListView exlist_lol;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置状态栏为透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
}
setContentView(R.layout.activity_travel_list_create);
mContext = TravelListCreateActivity.this;
exlist_lol = (ExpandableListView) findViewById(R.id.exlist_create);
//数据准备
// gData = new ArrayList<String>();
// iData = new ArrayList<ArrayList<ListItem>>();
gData.add("分类1");
gData.add("分类2");
// lData = new ArrayList<ListItem>();
//1组
lData.add(new ListItem("羽绒服", "1"));
lData.add(new ListItem("毛巾", "2"));
iData.add(lData);
//2组
lData = new ArrayList<ListItem>();
lData.add(new ListItem("洗面奶", "1"));
lData.add(new ListItem("手机充电器", "2"));
iData.add(lData);
final MyBaseExpandableListAdapter1 myAdapter = new MyBaseExpandableListAdapter1(gData, iData, mContext);
exlist_lol.setAdapter(myAdapter);
myAdapter.setOnClickListenerEditOrDelete(new MyBaseExpandableListAdapter1.OnClickListenerEditOrDelete() {
@Override
public void OnClickListenerDelete(int groupPosition, int position) {
Toast.makeText(mContext, "删除第" + groupPosition+"组的第"+position+"个值", Toast.LENGTH_SHORT).show();
iData.get(groupPosition).remove(position);//删除选中的某列
if (iData.get(groupPosition).size() <= 0){//如果删除后,该组下没成员,那么移除标题和该组的数据集合
iData.remove(groupPosition);
gData.remove(groupPosition);
}
myAdapter.notifyDataSetChanged();//通知Adapter更新数据
}
});
for (int i = 0; i < iData.size(); i++) {//首次加载就全部打开
exlist_lol.expandGroup(i);
}
//为列表设置点击事件
// exlist_lol.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
// @Override
// public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
// Toast.makeText(mContext, "你点击了:" + iData.get(groupPosition).get(childPosition).getiName(), Toast.LENGTH_SHORT).show();
// return true;
// }
// });
// exlist_lol.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {//把ExpandableListView的组点击事件屏蔽,不能点击收缩
// @Override
// public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
// return true;
// }
// });
}
}
6、实体类
public class ListItem {
private String iName;
private String iNum;
public ListItem() {
}
public ListItem(String iName,String iNum) {
this.iName = iName;
this.iNum = iNum;
}
public String getiName() {
return iName;
}
public String getiNum() {
return iNum;
}
public void setiName(String iName) {
this.iName = iName;
}
public void setiNum(String iNum) {
this.iNum = iNum;
}
}
7、自定义的SlideExpandableListView.java,在java下的MyUI文件夹下
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
/**
* Created by peng on 2018/4/18.
*/
public class SlideExpandableListView extends ExpandableListView {
private int mScreenWidth; // 屏幕宽度
private int mDownX; // 按下点的x值
private int mDownY; // 按下点的y值
private int mDeleteBtnWidth;// 删除按钮的宽度
private boolean isDeleteShown; // 删除按钮是否正在显示
private ViewGroup mPointChild; // 当前处理的item
private LinearLayout.LayoutParams mLayoutParams; // 当前处理的item的LayoutParams
public SlideExpandableListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlideExpandableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 获取屏幕宽度
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
mScreenWidth = dm.widthPixels;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://初次触摸
performActionDown(ev);
break;
case MotionEvent.ACTION_MOVE://滑动
super.onTouchEvent(ev);//调用父类方法,防止滑动时触发点击事件
return performActionMove(ev);
case MotionEvent.ACTION_UP://抬起
performActionUp();
break;
}
return super.onTouchEvent(ev);
}
// 处理action_down事件
private void performActionDown(MotionEvent ev) {
if(isDeleteShown) {
turnToNormal();
}
mDownX = (int) ev.getX();
mDownY = (int) ev.getY();
// 获取当前点的item
mPointChild = (ViewGroup) getChildAt(pointToPosition(mDownX, mDownY)
- getFirstVisiblePosition());
// 获取删除按钮的宽度
mDeleteBtnWidth = mPointChild.getChildAt(1).getLayoutParams().width;
mLayoutParams = (LinearLayout.LayoutParams) mPointChild.getChildAt(0)
.getLayoutParams();
mLayoutParams.width = mScreenWidth;
mPointChild.getChildAt(0).setLayoutParams(mLayoutParams);
}
// 处理action_move事件
private boolean performActionMove(MotionEvent ev) {
int nowX = (int) ev.getX();
int nowY = (int) ev.getY();
if(Math.abs(nowX - mDownX) > Math.abs(nowY - mDownY)) {
// 如果向左滑动
if(nowX < mDownX) {
// 计算要偏移的距离
int scroll = (nowX - mDownX) / 2;
// 如果大于了删除按钮的宽度, 则最大为删除按钮的宽度
if(-scroll >= mDeleteBtnWidth) {
scroll = -mDeleteBtnWidth;
}
// 重新设置leftMargin
mLayoutParams.leftMargin = scroll;
mPointChild.getChildAt(0).setLayoutParams(mLayoutParams);
}
return true;
}
return super.onTouchEvent(ev);
}
// 处理action_up事件
private void performActionUp() {
// 偏移量大于button的一半,则显示button
// 否则恢复默认
if(-mLayoutParams.leftMargin >= mDeleteBtnWidth / 2) {
mLayoutParams.leftMargin = -mDeleteBtnWidth;
isDeleteShown = true;
}else {
turnToNormal();
}
mPointChild.getChildAt(0).setLayoutParams(mLayoutParams);
}
/**
* 变为正常状态
*/
public void turnToNormal() {
mLayoutParams.leftMargin = 0;
mPointChild.getChildAt(0).setLayoutParams(mLayoutParams);
isDeleteShown = false;
}
/**
* 当前是否可点击
* @return 是否可点击
*/
public boolean canClick() {
return !isDeleteShown;
}
}
图片:icon_minus和icon_add(上传不显示,可以网上下载下,就是加减好的图片)放在mipmap下即可:
问题:
这样的通过自定义组件的方式,对listview还好,对expandablelistview就有个问题,左滑显示删除按钮只能在点击了某个列后才能生效,即只有单击后才能滑动,否则会不响应或者直接退出APP;