【android自定义控件】android ListView添加侧滑删除

为ListView添加炫酷的Item中带侧滑的删除,原理是利用item布局中的padding(Left和Right)属性为负值,来把删除的按钮隐藏在屏幕外。然后通过自定义ListView重写其中的OnTouchEvent通过手指坐标点的计算来处理事件,实现itemView的滚动,达到滑动出现删除菜单,本例中仅实现右向左滑出现删除按钮,大家可以根据自己需求,参照自定义ListView中事件处理做出左侧滑,右侧滑出现菜单,当然不仅仅局限于删除。更多灵活用法期待发觉。

首先上自定义的ListSlideView代码,其中有有详细注释,我就不废话了!(该ListView参考以前项目里面的事件分发处理判断,具体参考了哪位大神的写法已无法考究,感谢最原先的作者的同时也请见谅,如见可联系博主,把参考出处加上)

ListSlideView:

/**
 * ListSlideView.java
 * 2015 下午3:00:24
 */
package com.example.slideviewtest;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Scroller;

/**
 * @note 自定义的listView,集成自系统的ListView,对list的OnTouchEnvent事件分发进行了拦截处理(最关键的地方,
 *       也是通过该方式实现了控制屏幕外布局的拖拽) 需要配合Item的布局文件来实现
 * @author blank
 * @time 下午3:00:24
 * @version V1.0
 */
public class ListSlideView extends ListView {

	/** 禁止侧滑模式 */
	public static int MODE_FORBID = 0;
	/** 从右向左滑出菜单模式 */
	public static int MODE_RIGHT = 1;
	/** 当前的模式 */
	private int mode = MODE_FORBID;
	/** 右侧菜单的长度 */
	private int rightLength = 0;

	/**
	 * 当前滑动的ListView position
	 */
	private int slidePosition;
	/**
	 * 手指按下X的坐标
	 */
	private int downY;
	/**
	 * 手指按下Y的坐标
	 */
	private int downX;
	/**
	 * ListView的item
	 */
	private View itemView;
	/**
	 * 滑动类
	 */
	private Scroller scroller;
	/**
	 * 认为是用户滑动的最小距离
	 */
	private int mTouchSlop;

	/**
	 * 判断是否可以侧向滑动
	 */
	private boolean canMove = false;
	/**
	 * 标示是否完成侧滑
	 */
	private boolean isSlided = false;

	public ListSlideView(Context context) {
		this(context, null);
	}

	public ListSlideView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.SlideMode);
		mode = a.getInt(R.styleable.SlideMode_mode, 0);
	}

	public ListSlideView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.SlideMode);
		mode = a.getInt(R.styleable.SlideMode_mode, 0);
		scroller = new Scroller(context);
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
	}

	/**
	 * 处理我们拖动ListView item的逻辑
	 */
	@Override
	public boolean onTouchEvent(MotionEvent ev) {

		final int action = ev.getAction();
		int lastX = (int) ev.getX();

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			System.out.println("touch-->" + "down");

			/* 默认不处理当前View的事件,即没有侧滑菜单 */
			if (this.mode == MODE_FORBID) {
				return super.onTouchEvent(ev);
			}

			// 侧滑状态判断
			if (isSlided) {
				scrollBack();
				return false;
			}
			// 滚动是否结束
			if (!scroller.isFinished()) {
				return false;
			}
			downX = (int) ev.getX();
			downY = (int) ev.getY();

			slidePosition = pointToPosition(downX, downY);

			// 无效的position
			if (slidePosition == AdapterView.INVALID_POSITION) {
				return super.onTouchEvent(ev);
			}

			itemView = getChildAt(slidePosition - getFirstVisiblePosition());

			/* 右侧菜单的长度 */
			if (this.mode == MODE_RIGHT) {
				this.rightLength = -itemView.getPaddingRight();
			}

			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("touch-->" + "move");

			if (!canMove
					&& slidePosition != AdapterView.INVALID_POSITION
					&& (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev
							.getY() - downY) < mTouchSlop)) {
				int offsetX = downX - lastX;
				if (offsetX > 0 && this.mode == MODE_RIGHT) {
					/* 从右向左滑 */
					canMove = true;
				} else {
					canMove = false;
				}
				/* 侧滑时ListView的OnItemClickListener事件的屏蔽 */
				MotionEvent cancelEvent = MotionEvent.obtain(ev);
				cancelEvent
						.setAction(MotionEvent.ACTION_CANCEL
								| (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
				onTouchEvent(cancelEvent);
			}
			if (canMove) {
				/* 侧滑动时,ListView不上下滚动 */
				requestDisallowInterceptTouchEvent(true);

				// 根据X坐标的差可以得到手指滑动方向,本例子可以根据自己的需要去灵活修改(左边划出菜单,右边划出菜单,或者左右均可)
				int deltaX = downX - lastX;
				if (deltaX > 0 && this.mode == MODE_RIGHT) {
					/* X坐标差大于0手指向右滑动 */
					itemView.scrollTo(deltaX, 0);
				} else {
					itemView.scrollTo(0, 0);
				}
				return true;
			}
		case MotionEvent.ACTION_UP:
			System.out.println("touch-->" + "up");
			if (canMove) {
				canMove = false;
				scrollByDistanceX();
			}
			break;
		}
		return super.onTouchEvent(ev);
	}

	/**
	 * 根据手指滚动itemView的距离来判断是滚动到开始位置还是向左或者向右滚动
	 */
	private void scrollByDistanceX() {
		/* 当前模式不允许滑动,则直接返回 */
		if (this.mode == MODE_FORBID) {
			return;
		}
		if (itemView.getScrollX() > 0 && this.mode == MODE_RIGHT) {
			/* 从右向左滑 */
			if (itemView.getScrollX() >= rightLength / 2) {
				scrollLeft();
			} else {
				// 滚回原始位置
				scrollBack();
			}
		} else {
			// 滚回原始位置
			scrollBack();
		}

	}

	/**
	 * 向左滑动
	 */
	private void scrollLeft() {
		isSlided = true;
		final int delta = (rightLength - itemView.getScrollX());
		// 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
		scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
				Math.abs(delta));
		postInvalidate(); // 刷新itemView
	}

	/**
	 * 侧滑菜单复原
	 */
	private void scrollBack() {
		isSlided = false;
		scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(),
				0, Math.abs(itemView.getScrollX()));
		postInvalidate(); // 刷新itemView
	}

	@Override
	public void computeScroll() {
		// 调用startScroll的时候scroller.computeScrollOffset()返回true,
		if (scroller.computeScrollOffset()) {
			// 让ListView item根据当前的滚动偏移量进行滚动
			itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());

			postInvalidate();
		}
	}

	/**
	 * 复原
	 */
	public void slideBack() {
		this.scrollBack();
	}

}

为了兼容以前的ListView添加了是否需要侧滑的自定义控件属性

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="SlideMode">
        <attr name="mode">
            <enum name="forbid" value="0"></enum>
            <enum name="right" value="1"></enum>
        </attr>
    </declare-styleable>

</resources>

0代表不支持侧滑,1代表支持右侧滑,可以根据自己需要去加上左侧滑

ItemView的布局:

<?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:background="@android:color/white"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingBottom="10dp"
    android:paddingRight="-90dp"
    android:paddingTop="10dp"
    android:weightSum="1" >

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="96dp"
        android:layout_weight="0.35"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/imgIcon"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:scaleType="fitXY"
            android:src="@drawable/images" />

        <TextView
            android:id="@+id/tvPrice"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="$128.5" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="96dp"
        android:layout_weight="0.65"
        android:orientation="vertical"
        android:padding="5dp" >

        <TextView
            android:id="@+id/tvName"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="HP 14-P010NR 14 TOUCHSCREEN SLATEBOOK, NIVIDIA TE"
            android:textStyle="bold" />

        <RatingBar
            android:id="@+id/ratingBar"
            style="?android:attr/ratingBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:numStars="5" />
    </LinearLayout>

    <TextView
        android:id="@+id/tvDelete"
        android:layout_width="90dp"
        android:layout_height="96dp"
        android:layout_centerInParent="true"
        android:layout_marginRight="-5dp"
        android:background="@android:color/holo_red_light"
        android:gravity="center"
        android:text="Delete"
        android:textColor="@android:color/white"
        android:textSize="15sp" />

</LinearLayout>

为了适配ListSlideView的适配器:

package com.example.slideviewtest;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
 * @author blank
 * @time 下午4:01:07
 * @version V1.0
 */
public class SlideViewAdapter extends BaseAdapter {

	private Context mContext;
	private LayoutInflater layoutInflr;
	private int itemtype = 1;
	private OnRemoveListener mRemoveListener;

	public int getItemtype() {
		return itemtype;
	}

	public void setItemtype(int itemtype) {
		this.itemtype = itemtype;
	}

	public SlideViewAdapter( Context context) {
		this.mContext = context;
		this.layoutInflr = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

	}

	public void setRemoveListener(OnRemoveListener removeListener) {
		this.mRemoveListener = removeListener;
	}

	class Viewlayout {
		private TextView mDelete;// 隐藏的侧滑删除按钮

	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return 10;
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {
		Viewlayout icom_view;
		if (convertView == null) {
			icom_view = new Viewlayout();
			convertView = layoutInflr.inflate(R.layout.item_product_listview,
					null);
			icom_view.mDelete = (TextView) convertView
					.findViewById(R.id.tvDelete);
			convertView.setTag(icom_view);
		} else {
			icom_view = (Viewlayout) convertView.getTag();
		}
		icom_view.mDelete.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				if(mRemoveListener!=null){mRemoveListener.onRemoveItem(position);}
			}
		});

		return convertView;
	}

	public interface OnRemoveListener {
		void onRemoveItem(int position);
	}

}

demo没有做数据填充,把删除的事件回调出去了!

来2张效果图:










源码地址已修改为正确地址


源码下载地址:源码下载


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值