Android 自定义ListView控件,滑动删除

1、触摸事件 dispatchTouchEvent 判断是否处理触摸动作 onTouchEvent 处理触摸动作

2、Android对于控制和获取View在屏幕很强大

ListView:

pointToPosition 根据触摸点获取item的位置

getChildAt 根据索引获取item的View,注意从第一个可视化的item算起

View:

getLocationOnScreen获取View在屏幕的坐标

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;

public class MyListView extends ListView
{

    private static final String TAG = "MyListView";

    // private static final int VELOCITY_SANP = 200;
    // private VelocityTracker mVelocityTracker;
    /**
     * 用户滑动的最小距离
     */
    private int touchSlop;

    /**
     * 是否响应滑动
     */
    private boolean isSliding;

    /**
     * 手指按下时的x坐标
     */
    private int xDown;
    /**
     * 手指按下时的y坐标
     */
    private int yDown;
    /**
     * 手指移动时的x坐标
     */
    private int xMove;
    /**
     * 手指移动时的y坐标
     */
    private int yMove;

    private LayoutInflater mInflater;

    private PopupWindow mPopupWindow;
    private int mPopupWindowHeight;
    private int mPopupWindowWidth;

    private Button mDelBtn;
    /**
     * 为删除按钮提供一个回调接口
     */
    private DelButtonClickListener mListener;

    /**
     * 当前手指触摸的View
     */
    private View mCurrentView;

    /**
     * 当前手指触摸的位置
     */
    private int mCurrentViewPos;

    /**
     * 必要的一些初始化
     *
     * @param context
     * @param attrs
     */
    public MyListView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        mInflater = LayoutInflater.from(context);
        // 获取设备所支持的最小滑动距离
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

        View view = mInflater.inflate(R.layout.button_list, null);
        mDelBtn = (Button) view.findViewById(R.id.id_item_btn1);
        //
        mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        /**
         * 先调用下measure,否则拿不到宽和高
         */
        mPopupWindow.getContentView().measure(0, 0);
        mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();
        mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        int action = ev.getAction();
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (action)
        {

            case MotionEvent.ACTION_DOWN:
                xDown = x;
                yDown = y;
                /**
                 * 如果当前popupWindow显示,则直接隐藏,然后屏蔽ListView的touch事件的下传
                 */
                if (mPopupWindow.isShowing())
                {
                    dismissPopWindow();
                    return false;
                }
                // 获得当前手指按下时的item的位置
                mCurrentViewPos = pointToPosition(xDown, yDown);
                // 获得当前手指按下时的item
                View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition());
                mCurrentView = view;
                break;
            case MotionEvent.ACTION_MOVE:
                xMove = x;
                yMove = y;
                int dx = xMove - xDown;
                int dy = yMove - yDown;
                /**
                 * 判断是否是从右到左的滑动
                 */
                if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop)
                {
                    // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx +
                    // " , dy = " + dy);
                    isSliding = true;
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        int action = ev.getAction();
        /**
         * 如果是从右到左的滑动才相应
         */
        if (isSliding)
        {
            switch (action)
            {
                case MotionEvent.ACTION_MOVE:

                    int[] location = new int[2];
                    // 获得当前item的位置x与y
                    mCurrentView.getLocationOnScreen(location);
                    // 设置popupWindow的动画
                    mPopupWindow.setAnimationStyle(R.style.button_anim_style);
                    mPopupWindow.update();
                    mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP,
                            location[0] + mCurrentView.getWidth(), location[1]);// + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2);
                    // 设置删除按钮的回调
                    mDelBtn.setOnClickListener(new OnClickListener()
                    {
                        @Override
                        public void onClick(View v)
                        {
                            if (mListener != null)
                            {
                                mListener.clickHappend(mCurrentViewPos);
                                mPopupWindow.dismiss();
                            }
                        }
                    });
                    // Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight);

                    break;
                case MotionEvent.ACTION_UP:
                    isSliding = false;

            }
            // 相应滑动期间屏幕itemClick事件,避免发生冲突
            return true;
        }

        return super.onTouchEvent(ev);
    }

    /**
     * 隐藏popupWindow
     */
    private void dismissPopWindow()
    {
        if (mPopupWindow != null && mPopupWindow.isShowing())
        {
            mPopupWindow.dismiss();
        }
    }

    public void setDelButtonClickListener(DelButtonClickListener listener)
    {
        mListener = listener;
    }

    interface DelButtonClickListener
    {
        public void clickHappend(int position);
    }

}

 

posted on 2015-08-03 16:28  2015xbx  阅读(260)  评论(0编辑  收藏  举报

导航