Android开发--自定义控件实现listview的滑动删除item

来源:互联网 发布:linux系统界面 编辑:程序博客网 时间:2024/05/17 03:56
首先我们在日常的软件使用中已经有很多这样的例子了,例如我们用到的QQ、微信都具有这样的功能。
而本文只是简单的起一个引导的作用,在已经存在的listview的基础上对其进行改造,使它能更好的满足
我们在开发当中遇到的需求。

首先,我们先看下我们要达到的效果:





看到效果图,首先我们来思考一下,要实现这样的效果,我们需要进行怎样的步骤? 
思路:可以确定的是,我们肯定通过手势的从右自左的滑动,这样,我们就想肯定要获取到滑动之前的X,Y坐标和滑动结束的X,Y坐标
通过判断开始和结束时坐标距离的绝对值来计算出滑动的距离。在这之前,我们应该设置一个值,来表示当大于这个值时。
我们就应该响应滑动事件,及显示删除按钮。如何显示一个删除按钮呢?我们这儿采用Android自带的一个控件:PopupWindow。

通过上面简单的分析之后,我们就来看具体的代码实现。然后在慢慢了解编码过程中,我们需要注意的细节问题。

首先,来看下目录结构:


准备两个布局文件:1、activity_main.xml 主界面布局文件。2、btn_delete.xml Button删除按钮的布局文件

下面是布局文件的具体代码实现:

activity_main.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">    <com.hql.listviewitemdelete.widget.ListViewDeleteItem        android:id="@+id/list_item_delete"        android:layout_width="match_parent"        android:layout_height="match_parent">    </com.hql.listviewitemdelete.widget.ListViewDeleteItem></LinearLayout>

btn_delete.xml:

<?xml version="1.0" encoding="utf-8"?><Button    android:id="@+id/btn_delete"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="#ff0202"    android:text="删除"/>

布局文件都很简单,相信大家都能看得懂。

接下来,我们就来编写ListViewDeleteItem,这个类,因为我们是在listview进行扩展开发,所以我们应该是继承自listview。
/** * listview滑动删除item * Created by Mr.H on 2015/11/16. */public class ListViewDeleteItem extends ListView

接下来我们根据刚刚的思路,首先应该定义一下变量:开始X,Y坐标、结束X,Y坐标、相应滑动的距离、是否正在滑动、布局加载器、
PopupWindow、PopupWindow宽高、删除按钮Button、删除按钮的回调接口、手指现在触摸到的view、和手指触摸到的view的位置。
以上就是我们应该要定义的成员变量。

 //手指按下的X,Y坐标    private int startX;    private int startY;    //手指移动结束时的X,Y坐标    private int endX;    private int endY;    //用户手势滑动的距离    private int moveLength;    //是否正在滑动    private boolean isSliding;    //布局加载器    private LayoutInflater mInflater;    //pop弹出    private PopupWindow mPopupWindow;    //pop高度    private int mPopupWindowHeight;    //pop宽度    private int mPopupWindowWidth;    //删除按钮    private Button mBtnDelete;    //删除按钮的回调接口    public BtnDeleteClickListener mListener;    //当前手指触摸的View    private View mCurrentView;    //当前手指触摸的位置    private int mCurrentViewPos;

现在我们需要重写含有两个参数的构造方法,并对部分变量就行初始化。

public ListViewDeleteItem(Context context, AttributeSet attrs)    {        super(context, attrs);        //实例化布局加载器        mInflater = LayoutInflater.from(context);        //getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件,如果小于这个距离就不触发移动控件。        moveLength = ViewConfiguration.get(context).getScaledTouchSlop();        //获取到删除按钮的布局文件        View view = mInflater.inflate(R.layout.btn_delete, null);        //查找删除按钮        mBtnDelete = (Button) view.findViewById(R.id.btn_delete);        //实例化POP,并且绑定视图,和设置宽高        mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);        //先调用下measure,否则拿不到宽和高        mPopupWindow.getContentView().measure(0, 0);        //获取button的宽高        mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();        mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();    }

上面的主要是对布局加载器进行初始化,加载一个布局文件,然后绑定到PopupWindow中,并且测出button在PopupWindow中的宽高。

做完以上操作,我们现在就需要实现我们最重要的部分了,即手势的判断。

接下来我们重写dispatchTouchEvent(MotionEvent ev)这个方法。这个方法主要是对点击事件的分发。
首先,我们通过 ev 这个参数来获取到用户的点击事件类型,并且用两个局部变量,记录下点击时的X,Y坐标。
//获取点击类型        int actiion = ev.getAction();        //获取按下时的x,y坐标        int x = (int) ev.getX();        int y = (int) ev.getY();

对此,我们应该判断用户的两个动作:按下和移动

首先我们先来看按下事件的处理:
 switch (actiion)        {            //按下            case MotionEvent.ACTION_DOWN:                startX = x;                startY = y;                //如果当前的pop显示,则将其隐藏掉                if (mPopupWindow.isShowing())                {                    dismissPopWindow();                    return false;                }                // 获得当前手指按下时的item的位置                mCurrentViewPos = pointToPosition(startX, startY);                // 获得当前手指按下时的item                View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition());                mCurrentView = view;                break;

将开始获取到的X,Y坐标赋值给定义的变量。并且判断PopupWindow是否正在显示,如果是则关闭,并且返回false。

之后通过pointToPosition()方法获取到当前按下的item的位置。通过getChildAt()获取到当前点击item位置所对应的view。
以上就是用户按下的事件。

下面来处理用户移动时的事件。
 //移动            case MotionEvent.ACTION_MOVE:                endX = x;                endY = y;                int dx = endX - startX;                int dy = endY - startY;                /**                 * 判断是否是从右到左的滑动                 */                if (endX < startX && Math.abs(dx) > moveLength && Math.abs(dy) < moveLength)                {                    isSliding = true;                }                break;

上面是对事件的分发处理,下面我们就来看看事件的处理即:onTouchEvent(MotionEvent ev)方法。
int action = ev.getAction();        if (isSliding)        {            switch (action)            {                case MotionEvent.ACTION_UP:                    isSliding = false;                    break;                case MotionEvent.ACTION_MOVE:                    int[] location = new int[2];                    mCurrentView.getLocationOnScreen(location);                    //设置pop显示的位置                    mPopupWindow.showAtLocation                            (mCurrentView, Gravity.LEFT | Gravity.TOP,                                    location[0] + mCurrentView.getWidth(),                                    location[1] + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2);                    mBtnDelete.setOnClickListener(new OnClickListener()                    {                        @Override                        public void onClick(View view)                        {                            if (mListener != null)                            {                                mListener.btnClick(mCurrentViewPos);                                mPopupWindow.dismiss();                            }                        }                    });                    break;            }        }        return super.onTouchEvent(ev);

首先,我还是要先获取到用户的点击事件类型,并且判断是否正在移动,当用户手势抬起的时候,将是否正在滑动设置为false。
处理用户移动的事件,设置PopupWindow的显示位置,并且给button设置点击事件。
public void setBtnDeleteClickListener(BtnDeleteClickListener listener)    {        mListener = listener;    }    public interface BtnDeleteClickListener    {        void btnClick(int position);    }    /**     * 隐藏pop     */    private void dismissPopWindow()    {        if (mPopupWindow != null && mPopupWindow.isShowing())        {            mPopupWindow.dismiss();        }    }

上面就是定义一个接口并写隐藏pop的方法。以上全部就是自定义的全部代码。接下来只需要将其写到布局文件当中。

demo下载地址:http://download.csdn.net/detail/poison_h/9275487



2 0
原创粉丝点击