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

来源:互联网 发布:windows caffe mnist 编辑:程序博客网 时间:2024/05/17 23:38

为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的逻辑 */@Overridepublic 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);// 无效的positionif (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来滚动itemscroller.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}@Overridepublic 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;// 隐藏的侧滑删除按钮}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn 10;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic 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() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif(mRemoveListener!=null){mRemoveListener.onRemoveItem(position);}}});return convertView;}public interface OnRemoveListener {void onRemoveItem(int position);}}

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

来2张效果图:










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


源码下载地址:源码下载


1 0
原创粉丝点击