1. 程式人生 > >Android 個人相簿圖片拖拽排序

Android 個人相簿圖片拖拽排序

效果圖如下:

具體核心程式碼:

private ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            //設定監聽拖拽的方向
            int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            int swipeFlags = 0; 
            return makeMovementFlags(dragFlags, swipeFlags);
        }

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            int fromPosition = viewHolder.getAdapterPosition();//得到item原來的position
            int toPosition = target.getAdapterPosition();//得到目標position
            if ((toPosition == listImgData.size() - 1 || listImgData.size() - 1 == fromPosition) && TextUtils.equals(listImgData.get(listImgData.size() - 1), "add")) {
                return true;
            }
            //滑動事件
            Collections.swap(listImgData, viewHolder.getAdapterPosition(), target.getAdapterPosition());
            mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
            return false;
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        }

        @Override
        public boolean isLongPressDragEnabled() {
            //是否可拖拽
            return false;
        }

        @Override
        public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
            super.onSelectedChanged(viewHolder, actionState);
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                viewHolder.itemView.setScaleX(1.1f);
                viewHolder.itemView.setScaleY(1.1f);
            }
        }

        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
            if (!recyclerView.isComputingLayout()) {
                //拖拽結束後恢復view的狀態
                viewHolder.itemView.setScaleX(1.0f);
                viewHolder.itemView.setScaleY(1.0f);
            }
        }
    });

 

這裡是否可以拖拽都是靠 isLongPressDragEnabled  這個回撥設定的,如果設定fase是不能拖拽的,由於我這裡最後一個是不能進行拖拽的,但是設定false就全部不能進行拖拽了,我們的需要的效果就是其他可以拖拽,最後一個或者特定字元的不需要拖拽

先檢視原始碼,發現這裡使用了isLongPressDragEnabled

 private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {

        ItemTouchHelperGestureListener() {
        }

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = findChildView(e);
            if (child != null) {
                ViewHolder vh = mRecyclerView.getChildViewHolder(child);
                if (vh != null) {
                    if (!mCallback.hasDragFlag(mRecyclerView, vh)) {
                        return;
                    }
                    int pointerId = e.getPointerId(0);
                    // Long press is deferred.
                    // Check w/ active pointer id to avoid selecting after motion
                    // event is canceled.
                    if (pointerId == mActivePointerId) {
                        final int index = e.findPointerIndex(mActivePointerId);
                        final float x = e.getX(index);
                        final float y = e.getY(index);
                        mInitialTouchX = x;
                        mInitialTouchY = y;
                        mDx = mDy = 0f;
                        if (DEBUG) {
                            Log.d(TAG,
                                    "onlong press: x:" + mInitialTouchX + ",y:" + mInitialTouchY);
                        }
                        if (mCallback.isLongPressDragEnabled()) {
                            select(vh, ACTION_STATE_DRAG);
                        }
                    }
                }
            }
        }
    }

上面原始碼ItemTouchHelperGestureListener是手指拖拽的一個監聽

如果長按的時候isLongPressDragEnabled  返回false  ,控制元件就不會出現拖拽

 

上面程式碼用於監聽觸控手勢

觸控手勢的觸控監聽又由下面程式碼傳入觸控事件

最開始的觸控事件監聽是RecyclerView的

由此可見,重新自定義一個觸控手勢長按事件可滿足我們的需求

想法:需要拖拽執行就必須執行   select(vh, ACTION_STATE_DRAG); 

這個方法

看了看原始碼,尷尬,這個方法不能外部呼叫的,反正這個方法就是長按的時候可以讓你拖拽

繼續檢視剛剛的按個是否可以長按拖拽,發現旁邊有個  startDrag 的方法,

   /**
         * Returns whether ItemTouchHelper should start a drag and drop operation if an item is
         * long pressed.
         * <p>
         * Default value returns true but you may want to disable this if you want to start
         * dragging on a custom view touch using {@link #startDrag(ViewHolder)}.
         *
         * @return True if ItemTouchHelper should start dragging an item when it is long pressed,
         * false otherwise. Default value is <code>true</code>.
         * @see #startDrag(ViewHolder)
         */
        public boolean isLongPressDragEnabled() {
            return true;
        }

發現startDrag 裡面也是執行了 select(vh, ACTION_STATE_DRAG);   這個進行開始拖拽的

自定義手勢觸控程式碼:

public abstract class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

    private GestureDetectorCompat mGestureDetector;
    private RecyclerView recyclerView;

    public OnRecyclerItemClickListener(RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
        mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener());
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }

    private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null) {
                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);
                onItemClick(vh);
            }
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null) {
                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);
                onItemLongClick(vh);
            }
        }
    }

    public abstract void onItemClick(RecyclerView.ViewHolder vh);

    public abstract void onItemLongClick(RecyclerView.ViewHolder vh);

}

 

設定監聽:

 mRecyclerView.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecyclerView) {
            @Override
            public void onItemClick(RecyclerView.ViewHolder vh) {
            }

            @Override
            public void onItemLongClick(RecyclerView.ViewHolder vh) {
                //如果item不是最後一個,則執行拖拽
                if (vh.getLayoutPosition() != listImgData.size() - 1) {
                    helper.startDrag(vh);
                } else if (!TextUtils.equals(listImgData.get(listImgData.size() - 1), "add")) {
                    helper.startDrag(vh);
                }
            }
        });

上面就是大體程式碼了