侧滑删除ListView

根据网友的分享修改的例子,实现了listview侧滑删除效果。

当侧滑的距离小于屏幕尺寸三分之一的时候,就回复。否则如果向右侧滑动超过三分之一,就移动到右侧边界外,然后删除该子项,如果是向左侧滑动超过三分之一,就移动到左侧边界外,然后删除该子项。

自定义Listview:

public class SlideListView extends ListView {
    private Context mContext;
    private int screenWidth;
    private View itemView;
    private Scroller scroller;
    private TouchPoint downPoint = new TouchPoint(0, 0);
    private RemoveListListener removeListListener;

    public void setRemoveListListener(RemoveListListener listListener) {
        this.removeListListener = listListener;
    }

    public SlideListView(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

    public SlideListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }

    public SlideListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mContext = context;
        init();
    }

    private void init() {
        scroller = new Scroller(mContext);
        screenWidth = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
    }

    /**
     * 事件分发
     *
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //scroller滚动未结束
                if (!scroller.isFinished()) {
                    return super.dispatchTouchEvent(ev);
                }
                downPoint.setPointX((int) ev.getX());
                downPoint.setPointY((int) ev.getY());
                int itempos = pointToPosition(downPoint.getPointX(), downPoint.getPointY());
                //无效的item
                if (AdapterView.INVALID_POSITION == itempos) {
                    return super.dispatchTouchEvent(ev);
                }
                downPoint.setCurPos(itempos);
                downPoint.setDownX(downPoint.getPointX());
                //获取当前的item
                itemView = getChildAt(itempos - getFirstVisiblePosition());
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                MotionEvent cancelEvent = MotionEvent.obtain(ev);
                cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                        (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                onTouchEvent(cancelEvent);

                float curX = ev.getX();
                int space = downPoint.getPointX() - (int) curX;
                downPoint.setPointX((int) curX);
                itemView.scrollBy(space, 0);
                break;
            case MotionEvent.ACTION_UP:
                scrollDistanceX();
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 滑动
     */
    private void scrollItemAnim(int delta) {
        scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
                Math.abs(delta));
        postInvalidate();
    }

    private void scrollDistanceX() {
        //手指滑动的矢量距离
        int scrollAbs = downPoint.getPointX() - downPoint.getDownX();
        //以左侧边界为原点
        if (Math.abs(scrollAbs) < screenWidth / 3) {
            scrollItemAnim(scrollAbs);
        } else {
            if (scrollAbs > 0) {
                scrollItemAnim(-screenWidth + scrollAbs);
            } else {
                scrollItemAnim(screenWidth + scrollAbs);
            }
        }
//强制停止滑动
//        scroller.forceFinished(true);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()) {
            itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());
            postInvalidate();
            if (scroller.isFinished()) {
                if (null == removeListListener) {
                    throw new NullPointerException("null removelistener");
                } else {
                    if (screenWidth / 4 < Math.abs(downPoint.getPointX() - downPoint.getDownX())) {
                        removeListListener.removeItem(downPoint.getCurPos());
                    }
                }
            }
        }
    }

    public interface RemoveListListener {
        public void removeItem(int pos);
    }

    private class TouchPoint {
        private int pointX;
        private int pointY;
        private int curPos;
        private int downX;

        private TouchPoint(int pointX, int pointY) {
            this.pointX = pointX;
            this.pointY = pointY;
        }

        public int getPointX() {
            return pointX;
        }

        public void setPointX(int pointX) {
            this.pointX = pointX;
        }

        public int getPointY() {
            return pointY;
        }

        public void setPointY(int pointY) {
            this.pointY = pointY;
        }

        public int getCurPos() {
            return curPos;
        }

        public void setCurPos(int curPos) {
            this.curPos = curPos;
        }

        public int getDownX() {
            return downX;
        }

        public void setDownX(int downX) {
            this.downX = downX;
        }
    }
}

在dispatch中,处理事件的分发,让合适的事件才分发下去,在里面都有注释说明的。

获取屏幕的宽度,作为移动的距离大小的判断标准。

 screenWidth = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
获取移动的子项。

pointToPosition(downPoint.getPointX(), downPoint.getPointY());
itemView = getChildAt(itempos - getFirstVisiblePosition());
取消在滑动中对listive的其他点击等事件。

 MotionEvent cancelEvent = MotionEvent.obtain(ev);
                cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                        (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                onTouchEvent(cancelEvent);
对滑动的判断,是分为四种情况的,向左滑动长度是否超过屏幕宽度的三分之一,向右滑动长度是否超过屏幕宽度的三分之一,下面是优化后的情况。

 if (Math.abs(scrollAbs) < screenWidth / 3) {
            scrollItemAnim(scrollAbs);
        } else {
            if (scrollAbs > 0) {
                scrollItemAnim(-screenWidth + scrollAbs);
            } else {
                scrollItemAnim(screenWidth + scrollAbs);
            }
        }
scroll没有停止的时候,可以强制停止。

//强制停止滑动
//        scroller.forceFinished(true);
声明的删除接口,给Listview提供移动删除的item。

public interface RemoveListListener {
        public void removeItem(int pos);
    }

computeScroll()源码注释,在这  我们使用了scroller.startScroll。

/**Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a Scroller object.*/
    public void  [More ...] computeScroll() {
    }
 /**
     * Start scrolling by providing a starting point and the distance to travel.
     * 
     * @param startX Starting horizontal scroll offset in pixels. Positive
     *        numbers will scroll the content to the left.
     * @param startY Starting vertical scroll offset in pixels. Positive numbers
     *        will scroll the content up.
     * @param dx Horizontal distance to travel. Positive numbers will scroll the
     *        content to the left.
     * @param dy Vertical distance to travel. Positive numbers will scroll the
     *        content up.
     * @param duration Duration of the scroll in milliseconds.
     */
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;
        mDurationReciprocal = 1.0f / (float) mDuration;
    }
看到了吧,里面使用了动画来移动子项。

scrollTo()与scrollBy(),scrollBy()其实调用了scrollTo(),只是在传入的是x,y的偏移量。而scrollTo()y移动的是实际距离。

 /**
     * Set the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the x position to scroll to
     * @param y the y position to scroll to
     */
    public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

    /**
     * Move the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the amount of pixels to scroll by horizontally
     * @param y the amount of pixels to scroll by vertically
     */
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

活动:

public class MainActivity extends Activity {
    private MainActivity mContext;
    private List<String> list = new ArrayList<String>();
    private SlideAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mContext = this;
        setData();
        SlideListView listView = (SlideListView) findViewById(R.id.slideview_list);
        adapter = new SlideAdapter();
        listView.setAdapter(adapter);
        listView.setRemoveListListener(new SlideListView.RemoveListListener() {
            @Override
            public void removeItem(int pos) {
                adapter.removeItem(pos);
            }
        });
    }

    private void setData() {
        String[] str = new String[]{"one", "two", "three", "four"};
        for (String s : str) {
            list.add(s);
        }
    }

    private class SlideAdapter extends BaseAdapter {

        private SlideAdapter() {

        }

        public void removeItem(int pos) {
            list.remove(pos);
            this.notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (null == convertView) {
                convertView = LayoutInflater.from(mContext).inflate(R.layout.item, null);
            }

            TextView textView = (TextView) convertView.findViewById(R.id.textView);
            textView.setText(list.get(position));
            return convertView;
        }
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值