Android源代码学习笔记:SlideAndDragListView-master


 

效果图:

 

1.lsitview中view元素的设置。

在源代码中设置了menu了,从而实现了listview的一系列应用效果。

    1.menuItem类封装了每一行的各种属性

  

public MenuItem(int width, String text, int textSize, int textColor, Drawable icon, Drawable background, int direction) {
        this.width = width;
        this.text = text;
        this.textSize = textSize;
        this.textColor = textColor;
        this.icon = icon;
        this.background = background;
        this.direction = direction;
    }

其中,在该类文件中还有一个bulider类,用于快速新建一个Menuitem

 public MenuItem build() {
            return new MenuItem(width, text, textSize, textColor, icon, background, direction);
        }

  2.menu。

  在listview中的每一行都是一个menu。menu中又有几个menuItem,用于实现,当手指向右滑动时,显现的小图标。

mLeftMenuItems = new ArrayList<>();  mRightMenuItems = new ArrayList<>();mLeftMenuItems是左边的小图标的集合,mRightMenuItems是右边的小图标的集合。

    public Menu(Drawable itemBackGroundDrawable, boolean wannaOver, int menuViewType) {
        mItemBackGroundDrawable = itemBackGroundDrawable;
        mWannaOver = wannaOver;
        mLeftMenuItems = new ArrayList<>();
        mRightMenuItems = new ArrayList<>();
        mMenuViewType = menuViewType;
    }


menu中封装了增减item的函数。

    public void addItem(MenuItem menuItem) {
        if (menuItem.direction == MenuItem.DIRECTION_LEFT) {
            mLeftMenuItems.add(menuItem);
        } else {
            mRightMenuItems.add(menuItem);
        }
    }

    public void addItem(MenuItem menuItem, int position) {
        if (menuItem.direction == MenuItem.DIRECTION_LEFT) {
            mLeftMenuItems.add(position, menuItem);
        } else {
            mRightMenuItems.add(position, menuItem);
        }
    }

    public boolean removeItem(MenuItem menuItem) {
        if (menuItem.direction == MenuItem.DIRECTION_LEFT) {
            return mLeftMenuItems.remove(menuItem);
        } else {
            return mRightMenuItems.remove(menuItem);
        }
    }

通过adapter中设置的来创建不同的Menu

List<Menu> menuList = new ArrayList<>(2);
Menu menu0 = new Menu(new ColorDrawable(Color.WHITE), true, 0);
menu0.addItem(new MenuItem.Builder().setWidth(90)//set Width
                .setBackground(new ColorDrawable(Color.RED))// set background
                .setText("One")//set text string
                .setTextColor(Color.GRAY)//set text color
                .setTextSize(20)//set text size
                .build());
menu0.addItem(new MenuItem.Builder().setWidth(120)
                .setBackground(new ColorDrawable(Color.BLACK))
                .setDirection(MenuItem.DIRECTION_RIGHT)//set direction (default DIRECTION_LEFT)
                .setIcon(getResources().getDrawable(R.drawable.ic_launcher))// set icon
                .build());
Menu menu1 = new Menu(new ColorDrawable(Color.YELLOW), false, 1);
menu1.addItem(new MenuItem.Builder().setWidth(60)
                .setBackground(new ColorDrawable(Color.RED))
                .setText("Two")
                .setTextColor(Color.GRAY)
                .setTextSize(25)
                .build());
menu1.addItem(new MenuItem.Builder().setWidth(70)
                .setBackground(new ColorDrawable(Color.BLUE))
                .setText("Three")
                .setDirection(MenuItem.DIRECTION_RIGHT)
                .setTextColor(Color.BLACK)
                .setTextSize(20)
                .build());
menuList.add(menu0);
menuList.add(menu1);
listView.setMenu(menuList)

 

public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //获取出坐标来
                mXDown = (int) ev.getX();
                mYDown = (int) ev.getY();
                //当前state状态为按下
                mState = STATE_DOWN;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_2_DOWN:
            case MotionEvent.ACTION_POINTER_3_DOWN:
                removeLongClickMessage();
                mState = STATE_MORE_FINGERS;
                //消耗掉,不传递下去了
                return true;
            case MotionEvent.ACTION_MOVE:
                if (fingerNotMove(ev) && mState != STATE_SCROLL) {//手指的范围在50以内
                    sendLongClickMessage(pointToPosition(mXDown, mYDown));
                    mState = STATE_LONG_CLICK;
                } else if (fingerLeftAndRightMove(ev)) {//上下范围在50,主要检测左右滑动
                    removeLongClickMessage();
                    mState = STATE_SCROLL;
                    //将当前想要滑动哪一个传递给wrapperAdapter
                    int position = pointToPosition(mXDown, mYDown);
                    if (position != AdapterView.INVALID_POSITION) {
                        View view = getChildAt(position - getFirstVisiblePosition());
                        if (view instanceof ItemMainLayout) {
                            mWrapperAdapter.setSlideItemPosition(position);
                            //将事件传递下去
                            return super.dispatchTouchEvent(ev);
                        } else {
                            //消耗事件
                            return true;
                        }
                    } else {
                        //消耗事件
                        return true;
                    }
                } else {
                    removeLongClickMessage();
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mState == STATE_DOWN || mState == STATE_LONG_CLICK) {
                    int position = pointToPosition(mXDown, mYDown);
                    //是否ScrollBack了,是的话就不去执行onListItemClick操作了
                    int scrollBackState = scrollBack(position, ev.getX());
                    if (scrollBackState == RETURN_SCROLL_BACK_NOTHING) {
                        if (mOnListItemClickListener != null && mIsWannaTriggerClick) {
                            View v = getChildAt(position - getFirstVisiblePosition());
                            mOnListItemClickListener.onListItemClick(v, position);
                        }
                    }
                }
                removeLongClickMessage();
                mState = STATE_NOTHING;
                break;
            case MotionEvent.ACTION_POINTER_3_UP:
            case MotionEvent.ACTION_POINTER_2_UP:
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_CANCEL:
                mState = STATE_NOTHING;
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }


滑动功能主要用到了Android的Scroller类和View的scrollTo方法。在ItemMainLayout中的类中的onTouchEvent

public boolean onTouchEvent(MotionEvent ev) {
        getParent().requestDisallowInterceptTouchEvent(false);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mXDown = ev.getX();
                mYDown = ev.getY();
                //控件初始距离
                mLeftDistance = mItemCustomLayout.getLeft();
                //是否有要scroll的动向,目前没有
                mIsMoving = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (fingerNotMove(ev) && !mIsMoving) {//手指的范围在50以内
                    //执行ListView的手势操作
                    getParent().requestDisallowInterceptTouchEvent(false);
                } else if (fingerLeftAndRightMove(ev) || mIsMoving) {//上下范围在50,主要检测左右滑动
                    //是否有要scroll的动向
                    mIsMoving = true;
                    //执行控件的手势操作
                    getParent().requestDisallowInterceptTouchEvent(true);
                    float moveDistance = ev.getX() - mXDown;//这个往右是正,往左是负
                    //判断意图
                    if (moveDistance > 0) {//往右
                        if (mLeftDistance == 0) {//关闭状态
                            mIntention = INTENTION_LEFT_OPEN;
                            setBackGroundVisible(true, false);
                        } else if (mLeftDistance < 0) {//右边的btn显示出来的
                            mIntention = INTENTION_RIGHT_CLOSE;
                        } else if (mLeftDistance > 0) {//左边的btn显示出来的
                            mIntention = INTENTION_LEFT_ALREADY_OPEN;
                        }
                    } else if (moveDistance < 0) {//往左
                        if (mLeftDistance == 0) {//关闭状态
                            mIntention = INTENTION_RIGHT_OPEN;
                            setBackGroundVisible(false, true);
                        } else if (mLeftDistance < 0) {//右边的btn显示出来的
                            mIntention = INTENTION_RIGHT_ALREADY_OPEN;
                        } else if (mLeftDistance > 0) {//左边的btn显示出来的
                            mIntention = INTENTION_LEFT_CLOSE;
                        }
                    }
                    //计算出距离
                    switch (mIntention) {
                        case INTENTION_LEFT_OPEN:
                        case INTENTION_LEFT_ALREADY_OPEN:
                            //此时moveDistance为正数,mLeftDistance为0
                            float distanceLeftOpen = mLeftDistance + moveDistance;
                            if (!mWannaOver) {
                                distanceLeftOpen = distanceLeftOpen > mBtnLeftTotalWidth ? mBtnLeftTotalWidth : distanceLeftOpen;
                            }
                            //滑动
                            mItemCustomLayout.layout((int) distanceLeftOpen, mItemCustomLayout.getTop(),
                                    mItemCustomLayout.getWidth() + (int) distanceLeftOpen, mItemCustomLayout.getBottom());
                            break;
                        case INTENTION_LEFT_CLOSE:
                            //此时moveDistance为负数,mLeftDistance为正数
                            float distanceLeftClose = mLeftDistance + moveDistance < 0 ? 0 : mLeftDistance + moveDistance;
                            //滑动
                            mItemCustomLayout.layout((int) distanceLeftClose, mItemCustomLayout.getTop(),
                                    mItemCustomLayout.getWidth() + (int) distanceLeftClose, mItemCustomLayout.getBottom());
                            break;
                        case INTENTION_RIGHT_OPEN:
                        case INTENTION_RIGHT_ALREADY_OPEN:
                            //此时moveDistance为负数,mLeftDistance为0
                            float distanceRightOpen = mLeftDistance + moveDistance;
                            //distanceRightOpen为正数
                            if (!mWannaOver) {
                                distanceRightOpen = -distanceRightOpen > mBtnRightTotalWidth ? -mBtnRightTotalWidth : distanceRightOpen;
                            }
                            //滑动
                            mItemCustomLayout.layout((int) distanceRightOpen, mItemCustomLayout.getTop(),
                                    mItemCustomLayout.getWidth() + (int) distanceRightOpen, mItemCustomLayout.getBottom());
                            break;
                        case INTENTION_RIGHT_CLOSE:
                            //此时moveDistance为正数,mLeftDistance为负数
                            float distanceRightClose = mLeftDistance + moveDistance > 0 ? 0 : mLeftDistance + moveDistance;
                            //滑动
                            mItemCustomLayout.layout((int) distanceRightClose, mItemCustomLayout.getTop(),
                                    mItemCustomLayout.getWidth() + (int) distanceRightClose, mItemCustomLayout.getBottom());

                            break;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                switch (mIntention) {
                    case INTENTION_LEFT_CLOSE:
                    case INTENTION_LEFT_OPEN:
                    case INTENTION_LEFT_ALREADY_OPEN:
                        //如果滑出的话,那么就滑到固定位置(只要滑出了 mBtnLeftTotalWidth / 2 ,就算滑出去了)
                        if (Math.abs(mItemCustomLayout.getLeft()) > mBtnLeftTotalWidth / 2) {
                            //滑出
                            mIntention = INTENTION_LEFT_OPEN;
                            int delta = mBtnLeftTotalWidth - Math.abs(mItemCustomLayout.getLeft());
                            mScroller.startScroll(mItemCustomLayout.getLeft(), 0, delta, 0, SCROLL_TIME);
                            if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_OPEN) {
                                mOnItemSlideListenerProxy.onSlideOpen(this, MenuItem.DIRECTION_LEFT);
                            }
                            mScrollState = SCROLL_STATE_OPEN;
                        } else {
                            mIntention = INTENTION_LEFT_CLOSE;
                            //滑回去,归位
                            mScroller.startScroll(mItemCustomLayout.getLeft(), 0, -mItemCustomLayout.getLeft(), 0, SCROLL_TIME);
                            if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_CLOSE) {
                                mOnItemSlideListenerProxy.onSlideClose(this, MenuItem.DIRECTION_LEFT);
                            }
                            mScrollState = SCROLL_STATE_CLOSE;
                        }
                        break;
                    case INTENTION_RIGHT_CLOSE:
                    case INTENTION_RIGHT_OPEN:
                    case INTENTION_RIGHT_ALREADY_OPEN:
                        if (Math.abs(mItemCustomLayout.getLeft()) > mBtnRightTotalWidth / 2) {
                            //滑出
                            mIntention = INTENTION_RIGHT_OPEN;
                            int delta = mBtnRightTotalWidth - Math.abs(mItemCustomLayout.getLeft());
                            mScroller.startScroll(mItemCustomLayout.getLeft(), 0, -delta, 0, SCROLL_TIME);
                            if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_OPEN) {
                                mOnItemSlideListenerProxy.onSlideOpen(this, MenuItem.DIRECTION_RIGHT);
                            }
                            mScrollState = SCROLL_STATE_OPEN;
                        } else {
                            mIntention = INTENTION_RIGHT_CLOSE;
                            mScroller.startScroll(mItemCustomLayout.getLeft(), 0, -mItemCustomLayout.getLeft(), 0, SCROLL_TIME);
                            //滑回去,归位
                            if (mOnItemSlideListenerProxy != null && mScrollState != SCROLL_STATE_CLOSE) {
                                mOnItemSlideListenerProxy.onSlideClose(this, MenuItem.DIRECTION_RIGHT);
                            }
                            mScrollState = SCROLL_STATE_CLOSE;
                        }
                        break;
                }
                mIntention = INTENTION_ZERO;
                postInvalidate();
                mIsMoving = false;
                break;
            default:
                break;
        }
        return true;
    }

2.拖拽功能

public void onDragViewMoving(int position) .参数 position 是被拖动的item的现在所在的位置,同时onDragViewMoving这个方法会被不停的调用,因为一直在拖动,同时position也会改变。

public void onDragViewDown(int position) . 参数 position 是被拖动的item被放下的时候在SDLV中的位置。

public boolean onDrag(View v, DragEvent event) {
        final int action = event.getAction();
        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                return true;
            case DragEvent.ACTION_DRAG_ENTERED:
                return true;
            case DragEvent.ACTION_DRAG_LOCATION:
                //当前移动的item在ListView中的position
                int position = pointToPosition((int) event.getX(), (int) event.getY());
                //如果位置发生了改变
                if (mBeforeCurrentPosition != position) {
                    //有时候得到的position是-1(AdapterView.INVALID_POSITION),忽略掉
                    if (position >= 0) {
                        //判断是往上了还是往下了
                        mUp = position - mBeforeCurrentPosition <= 0;
                        //记录移动之后上一次的位置
                        mBeforeBeforePosition = mBeforeCurrentPosition;
                        //记录当前位置
                        mBeforeCurrentPosition = position;
                    }
                }
                moveListViewUpOrDown(position);
                //有时候为-1(AdapterView.INVALID_POSITION)的情况,忽略掉
                if (position >= 0) {
                    //判断是不是已经换过位置了,如果没有换过,则进去换
                    if (position != mCurrentPosition) {
                        if (mUp) {//往上
                            int realPosition = position - getHeaderViewsCount();
                            if (realPosition >= 0 && realPosition < mDataList.size()) {//这里判断就忽略了drag到header的情况
                                //只是移动了一格
                                if (position - mBeforeBeforePosition == -1) {
                                    T t = mDataList.get(realPosition);
                                    mDataList.set(realPosition, mDataList.get(realPosition + 1));
                                    mDataList.set(realPosition + 1, t);
                                } else {//一下子移动了好几个位置,其实可以和上面那个方法合并起来的
                                    T t = mDataList.get(mBeforeBeforePosition - getHeaderViewsCount());
                                    for (int i = mBeforeBeforePosition - getHeaderViewsCount(); i > realPosition; i--) {
                                        mDataList.set(i, mDataList.get(i - 1));
                                    }
                                    mDataList.set(realPosition, t);
                                }
                                mSDAdapter.notifyDataSetChanged();
                                //更新位置
                                mCurrentPosition = position;
                            }
                        } else {
                            //header部分不算,footer部分不算
                            int realPosition = position - getHeaderViewsCount();
                            if (realPosition > 0 && realPosition < mDataList.size()) {
                                if (position - mBeforeBeforePosition == 1) {
                                    T t = mDataList.get(realPosition);
                                    mDataList.set(realPosition, mDataList.get(realPosition - 1));
                                    mDataList.set(realPosition - 1, t);
                                } else {
                                    T t = mDataList.get(mBeforeBeforePosition - getHeaderViewsCount());
                                    for (int i = mBeforeBeforePosition - getHeaderViewsCount(); i < realPosition; i++) {
                                        mDataList.set(i, mDataList.get(i + 1));
                                    }
                                    mDataList.set(realPosition, t);
                                }
                                mSDAdapter.notifyDataSetChanged();
                                //更新位置
                                mCurrentPosition = position;
                            }
                        }
                    }
                }
                if (mOnDragListener != null) {
                    mOnDragListener.onDragViewMoving(mCurrentPosition);
                }
                return true;
            case DragEvent.ACTION_DRAG_EXITED:
                return true;
            case DragEvent.ACTION_DROP:
                mSDAdapter.notifyDataSetChanged();
                for (int i = 0; i < getLastVisiblePosition() - getFirstVisiblePosition(); i++) {
                    if (getChildAt(i) instanceof ItemMainLayout) {
                        ItemMainLayout view = (ItemMainLayout) getChildAt(i);
                        setItemVisible(view);
                    }
                }
                if (mOnDragListener != null) {
                    mOnDragListener.onDragViewDown(mCurrentPosition);
                }
                return true;
            case DragEvent.ACTION_DRAG_ENDED:
                return true;
            default:
                break;
        }
        return false;
    }

3.拖动item往上或往下:ListView的smoothScrollToPosition方法。

    private void moveListViewUpOrDown(int position) {
        //ListView中最上面的显示的位置
        int firstPosition = getFirstVisiblePosition();
        //ListView中最下面的显示的位置
        int lastPosition = getLastVisiblePosition();
        //能够往上的话往上
        if ((position == firstPosition || position == firstPosition + 1) && firstPosition != 0) {
            smoothScrollToPosition(firstPosition - 1);
        }
        //能够往下的话往下
        if ((position == lastPosition || position == lastPosition - 1) && lastPosition != getCount() - 1) {
            smoothScrollToPosition(lastPosition + 1);
        }
    }
//Item滑动监听器

SlideAndDragListView.OnSlideListener() {
            @Override
            public void onSlideOpen(View view, View parentView, int position, int direction) {

            }

            @Override
            public void onSlideClose(View view, View parentView, int position, int direction) {

            }
        });

//Item删除监听器

slideAndDragListView.setOnItemDeleteListener(new SlideAndDragListView.OnItemDeleteListener() {
            @Override
            public void onItemDelete(View view, int position) {

            }
        });

 

posted @ 2016-02-25 11:18  我是小光  阅读(421)  评论(0编辑  收藏  举报