美文网首页
RecyclerView-->拖拽排序,点击删除

RecyclerView-->拖拽排序,点击删除

作者: 谢尔顿 | 来源:发表于2018-03-04 07:18 被阅读111次

    效果图:

    整个界面只用了RecyclerView实现,实现拖拽功能主要用到的了ItemTouchHelper类,添加和删除功能主要用到了位移动画实现位移效果。下面我们看看每一个相关的代码类;

    • ClassifyAdapter.java
    public class ClassifyActivity extends AppCompatActivity {
    
    
        @BindView(R.id.recy)
        RecyclerView mRecy;
        private List<TagBean> items = new ArrayList<>();
        private List<TagBean> otherItems = new ArrayList<>();
        private ClassifyAdapter adapter;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_classify);
            ButterKnife.bind(this);
            setTitle("拖拽排序,点击删除");
            initData();
            init();
        }
    
        private void init() {
    
            GridLayoutManager manager = new GridLayoutManager(this, 4);
            mRecy.setLayoutManager(manager);
    
            ItemDragHelperCallback callback = new ItemDragHelperCallback();
            final ItemTouchHelper helper = new ItemTouchHelper(callback);
            //将ItemTouchHelper和RecyclerView建立关联
            helper.attachToRecyclerView(mRecy);
    
            adapter = new ClassifyAdapter(this, helper, items, otherItems, 1);
            manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    int viewType = adapter.getItemViewType(position);
                    //从效果可知,当是两个头布局的时候要占据一行
                    return viewType == ClassifyAdapter.TYPE_MY || viewType == ClassifyAdapter.TYPE_OTHER ? 1 : 4;
                }
            });
            mRecy.setAdapter(adapter);
            adapter.setOnMyChannelItemClickListener(new ClassifyAdapter.OnMyChannelItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {
                    Toast.makeText(ClassifyActivity.this, "要跳转了", Toast.LENGTH_SHORT).show();
                }
            });
            adapter.setmCompleteListener(new ClassifyAdapter.OnCompleteListener() {
                @Override
                public void onComplete(List<TagBean> list) {
                    Toast.makeText(ClassifyActivity.this, "完成了", Toast.LENGTH_SHORT).show();
                }
            });
        }
        private void initData() {
            items.add(new TagBean("推荐", 1));
            items.add(new TagBean("视频", 2));
            items.add(new TagBean("图片", 3));
            items.add(new TagBean("娱乐", 4));
            items.add(new TagBean("问答", 5));
            ...
        }
    }
    

    上面代码中我们主要关注的就是ItemDragHelperCallback和ClassifyAdapter,其他的代码中都有详细注释。

    • ItemDragHelperCallback.java
    public class ItemDragHelperCallback extends ItemTouchHelper.Callback {
    
        private static String TAG = ItemDragHelperCallback.class.getSimpleName();
    
        /**
         * 开始拖拽排序时被调用
         * @param recyclerView
         * @param viewHolder
         * @return
         */
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            Log.e(TAG,"getMovementFlags");
            int dragFlags;
            //针对第一个不能拖拽
            if (viewHolder.getAdapterPosition() == 1) {
                return 0;
            }
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager instanceof GridLayoutManager || manager instanceof StaggeredGridLayoutManager) {
                dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            } else {
                dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            }
            // 如果想支持滑动(删除)操作, swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END
            int swipeFlags = 0;
            return makeMovementFlags(dragFlags, swipeFlags);
        }
    
        /**
         * 在拖拽移动过程中被调用
         * @param recyclerView
         * @param viewHolder
         * @param target
         * @return
         */
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            Log.e(TAG,"onMove");
            // 不同Type之间不可移动
            if (viewHolder.getItemViewType() != target.getItemViewType()) {
                return false;
            }
    
            //如果目标点为第一个 也不能拖拽过去
            if(target.getAdapterPosition()==1){
                return false;
            }
            //ClassifyAdapter实现了OnItemMoveListener接口
            if (recyclerView.getAdapter() instanceof OnItemMoveListener) {
                OnItemMoveListener listener = ((OnItemMoveListener) recyclerView.getAdapter());
                listener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
            }
            return true;
        }
    
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    
        }
    
        /**
         * 在开始拖拽排序和结束拖拽时被调用
         * @param viewHolder
         * @param actionState
         */
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            Log.e(TAG,"onSelectedChanged");
            // 不在闲置状态
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                //我的频道ViewHolder实现了了OnDragVHListener接口
                if (viewHolder instanceof OnDragVHListener) {
                    OnDragVHListener itemViewHolder = (OnDragVHListener) viewHolder;
                    itemViewHolder.onItemSelected();
                }
            }
            super.onSelectedChanged(viewHolder, actionState);
        }
    
        /**
         * 排序完成后调用
         * @param recyclerView
         * @param viewHolder
         */
        @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            Log.e(TAG,"clearView");
            //我的频道ViewHolder实现了了OnDragVHListener接口
            if (viewHolder instanceof OnDragVHListener) {
                OnDragVHListener itemViewHolder = (OnDragVHListener) viewHolder;
                itemViewHolder.onItemFinish();
            }
            super.clearView(recyclerView, viewHolder);
        }
    
        @Override
        public boolean isLongPressDragEnabled() {
            // 不支持长按拖拽功能 手动控制
            return false;
        }
    
        @Override
        public boolean isItemViewSwipeEnabled() {
            // 不支持滑动功能
            return false;
        }
    }
    
    

    从上面除了注释,我们还要了解的是OnItemMoveListener和OnDragVHListener这两个接口。

    • OnItemMoveListener.java
    public interface OnItemMoveListener {
        //在条目移动时,被调用
        void onItemMove(int fromPosition, int toPosition);
    }
    
    • OnDragVHListener.java
    public interface OnDragVHListener {
        /**
         * Item被选中时触发
         */
        void onItemSelected();
    
    
        /**
         * Item在拖拽结束/滑动结束后触发
         */
        void onItemFinish();
    }
    

    从ItemDragHelperCallback 中我们发现这两个接口的所有方法都被调用了,那么具体实现方法逻辑的代码在哪呢,下面就是我们的重头戏adapter了。

    • ClassAdapter
    public class ClassifyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements OnItemMoveListener {
        // 我的频道 标题部分
        public static final int TYPE_MY_CHANNEL_HEADER = 0;
        // 我的频道
        public static final int TYPE_MY = 1;
        // 其他频道 标题部分
        public static final int TYPE_OTHER_CHANNEL_HEADER = 2;
        // 其他频道
        public static final int TYPE_OTHER = 3;
    
        // 我的频道之前的header数量  该demo中 即标题部分 为 1
        private static final int COUNT_PRE_MY_HEADER = 1;
        // 其他频道之前的header数量  该demo中 即标题部分 为 COUNT_PRE_MY_HEADER + 1
        private static final int COUNT_PRE_OTHER_HEADER = COUNT_PRE_MY_HEADER + 1;
    
        private static final long ANIM_TIME = 360L;
        private final Context mContext;
    
        // touch 点击开始时间
        private long startTime;
        // touch 间隔时间  用于分辨是否是 "点击"
        private static final long SPACE_TIME = 100;
    
        private LayoutInflater mInflater;
        private ItemTouchHelper mItemTouchHelper;
    
        // 是否为 编辑 模式
        private boolean isEditMode;
    
        private List<TagBean> mMyChannelItems = new ArrayList<>();
        private List<TagBean> mOtherChannelItems = new ArrayList<>();
        // 我的频道点击事件
        private OnMyChannelItemClickListener mChannelItemClickListener;
        private OnCompleteListener mCompleteListener;
        private int selectedType;
    
        public ClassifyAdapter(Context context, ItemTouchHelper helper, List<TagBean> mMyChannelItems,
                               List<TagBean> mOtherChannelItems, int selectedType) {
            this.mContext = context;
            this.mInflater = LayoutInflater.from(context);
            this.mItemTouchHelper = helper;
            this.mMyChannelItems = mMyChannelItems;
            this.mOtherChannelItems = mOtherChannelItems;
            this.selectedType = selectedType;
        }
    
        /**
         * 根据效果图我们知道该RecyclerView总共包含四种布局
         *
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            if (mMyChannelItems == null && position == 1) {
                return TYPE_OTHER_CHANNEL_HEADER;
            }
            if (position == 0) {    // 我的频道 标题部分
                return TYPE_MY_CHANNEL_HEADER;
            } else if (position == mMyChannelItems.size() + 1) {// 其他频道 标题部分
                return TYPE_OTHER_CHANNEL_HEADER;
            } else if (position > 0 && position < mMyChannelItems.size() + 1) {
                return TYPE_MY;
            } else {
                return TYPE_OTHER;
            }
        }
    
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            final View view;
            switch (viewType) {
                case TYPE_MY_CHANNEL_HEADER://我的频道的头布局
                    view = mInflater.inflate(R.layout.item_my_channel_header, parent, false);
                    final MyChannelHeaderViewHolder holder = new MyChannelHeaderViewHolder(view);
                    holder.tvBtnEdit.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (!isEditMode) {
                                startEditMode((RecyclerView) parent);
                                holder.tvBtnEdit.setText(R.string.finish);
                                holder.tvDescription.setText("拖拽可以排序");
                            } else {
                                cancelEditMode((RecyclerView) parent);
                                holder.tvBtnEdit.setText(R.string.edit);
                                holder.tvDescription.setText("点击进入频道");
                                mCompleteListener.onComplete(mMyChannelItems);
                            }
                        }
                    });
                    return holder;
    
                case TYPE_MY://我的频道的条目布局
                    view = mInflater.inflate(R.layout.item_my, parent, false);
                    final MyViewHolder myHolder = new MyViewHolder(view);
                    myHolder.imgEdit.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            clickMyChannelItem(myHolder, parent, v);
                        }
                    });
                    myHolder.textView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(final View v) {
                            clickMyChannelItem(myHolder, parent, v);
                        }
                    });
    
                    //我的频道条目的长按事件
                    myHolder.textView.setOnLongClickListener(new View.OnLongClickListener() {
                        @Override
                        public boolean onLongClick(final View v) {
                            if (!isEditMode) {
                                RecyclerView recyclerView = ((RecyclerView) parent);
                                startEditMode(recyclerView);
    
                                // header 按钮文字 改成 "完成"
                                View view = recyclerView.getChildAt(0);
                                if (view == recyclerView.getLayoutManager().findViewByPosition(0)) {
                                    TextView tvBtnEdit = (TextView) view.findViewById(R.id.tv_btn_edit);
                                    TextView tvDescription = (TextView) view.findViewById(R.id.tv_description);
                                    tvBtnEdit.setText(R.string.finish);
                                    tvDescription.setText("拖拽可以排序");
    
                                }
                            }
                            //调用ItemTouchHelper的开始拖拽方法
                            mItemTouchHelper.startDrag(myHolder);
                            return true;
                        }
                    });
    
                    myHolder.textView.setOnTouchListener(new View.OnTouchListener() {
                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            if (isEditMode) {
                                switch (MotionEventCompat.getActionMasked(event)) {
                                    case MotionEvent.ACTION_DOWN:
                                        startTime = System.currentTimeMillis();
                                        break;
                                    case MotionEvent.ACTION_MOVE:
                                        if (System.currentTimeMillis() - startTime > SPACE_TIME) {
                                            //调用ItemTouchHelper的开始拖拽方法
                                            mItemTouchHelper.startDrag(myHolder);
                                        }
                                        break;
                                    case MotionEvent.ACTION_CANCEL:
                                    case MotionEvent.ACTION_UP:
                                        startTime = 0;
                                        break;
                                }
    
                            }
                            return false;
                        }
                    });
                    return myHolder;
    
                case TYPE_OTHER_CHANNEL_HEADER://其他频道的头布局
                    view = mInflater.inflate(R.layout.item_other_channel_header, parent, false);
                    return new RecyclerView.ViewHolder(view) {
                    };
    
                case TYPE_OTHER://其他频道的条目布局
                    view = mInflater.inflate(R.layout.item_other, parent, false);
                    final OtherViewHolder otherHolder = new OtherViewHolder(view);
                    //其他频道条目的点击事件
                    otherHolder.textView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            RecyclerView recyclerView = ((RecyclerView) parent);
                            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
                            int currentPiosition = otherHolder.getAdapterPosition();
                            // 如果RecyclerView滑动到底部,移动的目标位置的y轴 - height
                            View currentView = manager.findViewByPosition(currentPiosition);
                            // 目标位置的前一个item  即当前MyChannel的最后一个
                            View preTargetView = manager.findViewByPosition(mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);
    
                            // 如果targetView不在屏幕内,则为-1  此时不需要添加动画,因为此时notifyItemMoved自带一个向目标移动的动画
                            // 如果在屏幕内,则添加一个位移动画
                            if (recyclerView.indexOfChild(preTargetView) >= 0) {
                                Logger.e("从其他频道到我的频道,用到了自定义动画");
                                int targetX = preTargetView.getLeft();
                                int targetY = preTargetView.getTop();
    
                                int targetPosition = mMyChannelItems.size() - 1 + COUNT_PRE_OTHER_HEADER;
    
                                GridLayoutManager gridLayoutManager = ((GridLayoutManager) manager);
                                int spanCount = gridLayoutManager.getSpanCount();
                                // target 在最后一行第一个
                                if ((targetPosition - COUNT_PRE_MY_HEADER) % spanCount == 0) {
                                    View targetView = manager.findViewByPosition(targetPosition);
                                    targetX = targetView.getLeft();
                                    targetY = targetView.getTop();
                                } else {
                                    targetX += preTargetView.getWidth();
    
                                    // 最后一个item可见
                                    if (gridLayoutManager.findLastVisibleItemPosition() == getItemCount() - 1) {
                                        // 最后的item在最后一行第一个位置
                                        if ((getItemCount() - 1 - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER) % spanCount == 0) {
                                            // RecyclerView实际高度 > 屏幕高度 && RecyclerView实际高度 < 屏幕高度 + item.height
                                            int firstVisiblePostion = gridLayoutManager.findFirstVisibleItemPosition();
                                            if (firstVisiblePostion == 0) {
                                                // FirstCompletelyVisibleItemPosition == 0 即 内容不满一屏幕 , targetY值不需要变化
                                                // // FirstCompletelyVisibleItemPosition != 0 即 内容满一屏幕 并且 可滑动 , targetY值 + firstItem.getTop
                                                if (gridLayoutManager.findFirstCompletelyVisibleItemPosition() != 0) {
                                                    int offset = (-recyclerView.getChildAt(0).getTop()) - recyclerView.getPaddingTop();
                                                    targetY += offset;
                                                }
                                            } else { // 在这种情况下 并且 RecyclerView高度变化时(即可见第一个item的 position != 0),
                                                // 移动后, targetY值  + 一个item的高度
                                                targetY += preTargetView.getHeight();
                                            }
                                        }
                                    } else {
                                        System.out.println("current--No");
                                    }
                                }
    
                                // 如果当前位置是otherChannel可见的最后一个
                                // 并且 当前位置不在grid的第一个位置
                                // 并且 目标位置不在grid的第一个位置
    
                                // 则 需要延迟250秒 notifyItemMove , 这是因为这种情况 , 并不触发ItemAnimator , 会直接刷新界面
                                // 导致我们的位移动画刚开始,就已经notify完毕,引起不同步问题
                                if (currentPiosition == gridLayoutManager.findLastVisibleItemPosition()
                                        && (currentPiosition - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER) % spanCount != 0
                                        && (targetPosition - COUNT_PRE_MY_HEADER) % spanCount != 0) {
                                    moveOtherToMyWithDelay(otherHolder);
                                } else {
                                    moveOtherToMy(otherHolder);
                                }
                                startAnimation(recyclerView, currentView, targetX, targetY);
    
                            } else {
                                moveOtherToMy(otherHolder);
                            }
                        }
                    });
                    return otherHolder;
            }
            return null;
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (holder instanceof MyViewHolder) {
    
                MyViewHolder myHolder = (MyViewHolder) holder;
                myHolder.textView.setText(mMyChannelItems.get(position - COUNT_PRE_MY_HEADER).getText());
                if (selectedType == -1 && position == 1) {
                    myHolder.textView.setTextColor(Color.RED);
                }
                if (mMyChannelItems.get(position - COUNT_PRE_MY_HEADER).getType() == selectedType) {
                    myHolder.textView.setTextColor(Color.RED);
                } else {
                    myHolder.textView.setTextColor(mContext.getResources().getColor(R.color.channel_item_color));
                }
                if (isEditMode) {
                    myHolder.imgEdit.setVisibility(View.VISIBLE);
                } else {
                    myHolder.imgEdit.setVisibility(View.INVISIBLE);
                }
    
            } else if (holder instanceof OtherViewHolder) {
    
                ((OtherViewHolder) holder).textView.setText(mOtherChannelItems.get(position - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER).getText());
    
            } else if (holder instanceof MyChannelHeaderViewHolder) {
    
                MyChannelHeaderViewHolder headerHolder = (MyChannelHeaderViewHolder) holder;
                if (isEditMode) {
                    headerHolder.tvBtnEdit.setText(R.string.finish);
                    headerHolder.tvDescription.setText("拖拽可以排序");
                } else {
                    headerHolder.tvBtnEdit.setText(R.string.edit);
                    headerHolder.tvDescription.setText("点击进入频道");
                }
            }
        }
    
        @Override
        public int getItemCount() {
            // 我的频道  标题 + 我的频道.size + 其他频道 标题 + 其他频道.size
            if (mMyChannelItems != null && mOtherChannelItems != null) {
                return mMyChannelItems.size() + mOtherChannelItems.size() + COUNT_PRE_OTHER_HEADER;
            } else {
                return COUNT_PRE_OTHER_HEADER;
            }
        }
    
        /**
         * 开始增删动画
         */
        private void startAnimation(RecyclerView recyclerView, final View currentView, float targetX, float targetY) {
            final ViewGroup viewGroup = (ViewGroup) recyclerView.getParent();
            final ImageView mirrorView = addMirrorView(viewGroup, recyclerView, currentView);
    
            Animation animation = getTranslateAnimator(
                    targetX - currentView.getLeft(), targetY - currentView.getTop());
            currentView.setVisibility(View.INVISIBLE);
            mirrorView.startAnimation(animation);
    
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    viewGroup.removeView(mirrorView);
                    if (currentView.getVisibility() == View.INVISIBLE) {
                        currentView.setVisibility(View.VISIBLE);
                    }
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
        }
    
        /**
         * 我的频道 移动到 其他频道
         *
         * @param myHolder
         */
        private void moveMyToOther(MyViewHolder myHolder) {
            int position = myHolder.getAdapterPosition();
    
            int startPosition = position - COUNT_PRE_MY_HEADER;
            if (startPosition > mMyChannelItems.size() - 1) {
                return;
            }
            TagBean item = mMyChannelItems.get(startPosition);
            mMyChannelItems.remove(startPosition);
            mOtherChannelItems.add(0, item);
    
            notifyItemMoved(position, mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER);
        }
    
        /**
         * 其他频道 移动到 我的频道
         *
         * @param otherHolder
         */
        private void moveOtherToMy(OtherViewHolder otherHolder) {
            int position = processItemRemoveAdd(otherHolder);
            if (position == -1) {
                return;
            }
            notifyItemMoved(position, mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);
        }
    
        /**
         * 其他频道 移动到 我的频道 伴随延迟
         *
         * @param otherHolder
         */
        private void moveOtherToMyWithDelay(OtherViewHolder otherHolder) {
            final int position = processItemRemoveAdd(otherHolder);
            if (position == -1) {
                return;
            }
            delayHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    notifyItemMoved(position, mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);
                }
            }, ANIM_TIME);
        }
    
        private Handler delayHandler = new Handler();
    
        private int processItemRemoveAdd(OtherViewHolder otherHolder) {
            int position = otherHolder.getAdapterPosition();
    
            int startPosition = position - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER;
            if (startPosition > mOtherChannelItems.size() - 1) {
                return -1;
            }
            TagBean item = mOtherChannelItems.get(startPosition);
            mOtherChannelItems.remove(startPosition);
            mMyChannelItems.add(item);
            return position;
        }
    
    
        /**
         * 添加需要移动的 镜像View
         */
        private ImageView addMirrorView(ViewGroup parent, RecyclerView recyclerView, View view) {
            /**
             * 我们要获取cache首先要通过setDrawingCacheEnable方法开启cache,然后再调用getDrawingCache方法就可以获得view的cache图片了。
             buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果cache没有建立,系统会自动调用buildDrawingCache方法生成cache。
             若想更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。
             当调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。
             */
            view.destroyDrawingCache();
            view.setDrawingCacheEnabled(true);
            final ImageView mirrorView = new ImageView(recyclerView.getContext());
            Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
            mirrorView.setImageBitmap(bitmap);
            view.setDrawingCacheEnabled(false);
            int[] locations = new int[2];
            view.getLocationOnScreen(locations);
            int[] parenLocations = new int[2];
            recyclerView.getLocationOnScreen(parenLocations);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(bitmap.getWidth(), bitmap.getHeight());
            params.setMargins(locations[0], locations[1] - parenLocations[1], 0, 0);
            parent.addView(mirrorView, params);
    
            return mirrorView;
        }
    
        @Override
        public void onItemMove(int fromPosition, int toPosition) {
            TagBean item = mMyChannelItems.get(fromPosition - COUNT_PRE_MY_HEADER);
            mMyChannelItems.remove(fromPosition - COUNT_PRE_MY_HEADER);
            mMyChannelItems.add(toPosition - COUNT_PRE_MY_HEADER, item);
            notifyItemMoved(fromPosition, toPosition);
        }
    
        /**
         * 开启编辑模式
         *
         * @param parent
         */
        private void startEditMode(RecyclerView parent) {
            isEditMode = true;
            int visibleChildCount = parent.getChildCount();
            for (int i = 2; i < visibleChildCount; i++) {
                View view = parent.getChildAt(i);
                ImageView imgEdit = (ImageView) view.findViewById(R.id.img_edit);
                if (imgEdit != null) {
                    imgEdit.setVisibility(View.VISIBLE);
                }
            }
        }
    
        /**
         * 完成编辑模式
         *
         * @param parent
         */
        private void cancelEditMode(RecyclerView parent) {
            isEditMode = false;
    
            int visibleChildCount = parent.getChildCount();
            for (int i = 0; i < visibleChildCount; i++) {
                View view = parent.getChildAt(i);
                ImageView imgEdit = (ImageView) view.findViewById(R.id.img_edit);
                if (imgEdit != null) {
                    imgEdit.setVisibility(View.INVISIBLE);
                }
            }
        }
    
        /**
         * 获取位移动画
         */
        private TranslateAnimation getTranslateAnimator(float targetX, float targetY) {
            TranslateAnimation translateAnimation = new TranslateAnimation(
                    Animation.RELATIVE_TO_SELF, 0f,
                    Animation.ABSOLUTE, targetX,
                    Animation.RELATIVE_TO_SELF, 0f,
                    Animation.ABSOLUTE, targetY);
            // RecyclerView默认移动动画250ms 这里设置360ms 是为了防止在位移动画结束后 remove(view)过早 导致闪烁
            translateAnimation.setDuration(ANIM_TIME);
            translateAnimation.setFillAfter(true);
            return translateAnimation;
        }
    
        public interface OnMyChannelItemClickListener {
            void onItemClick(View v, int position);
        }
    
        public interface OnCompleteListener {
            void onComplete(List<TagBean> list);
        }
    
        public void setOnMyChannelItemClickListener(OnMyChannelItemClickListener listener) {
            this.mChannelItemClickListener = listener;
        }
    
        public void setmCompleteListener(OnCompleteListener mCompleteListener) {
            this.mCompleteListener = mCompleteListener;
        }
    
        /**
         * 我的频道
         */
        class MyViewHolder extends RecyclerView.ViewHolder implements OnDragVHListener {
            @BindView(R.id.tv)
            TextView textView;
            @BindView(R.id.img_edit)
            ImageView imgEdit;
    
            public MyViewHolder(View itemView) {
                super(itemView);
                ButterKnife.bind(this, itemView);
            }
    
            /**
             * item 被选中时
             */
            @Override
            public void onItemSelected() {
                textView.setBackgroundResource(R.drawable.bg_channel_p);
            }
    
            /**
             * item 取消选中时
             */
            @Override
            public void onItemFinish() {
                textView.setBackgroundResource(R.drawable.bg_channel);
            }
        }
    
        /**
         * 其他频道
         */
        class OtherViewHolder extends RecyclerView.ViewHolder {
            @BindView(R.id.tv)
            TextView textView;
    
            public OtherViewHolder(View itemView) {
                super(itemView);
                ButterKnife.bind(this, itemView);
            }
        }
    
        /**
         * 我的频道  标题部分
         */
        class MyChannelHeaderViewHolder extends RecyclerView.ViewHolder {
            @BindView(R.id.tv_btn_edit)
            TextView tvBtnEdit;
            @BindView(R.id.tv_description)
            TextView tvDescription;
    
            public MyChannelHeaderViewHolder(View itemView) {
                super(itemView);
                ButterKnife.bind(this, itemView);
            }
        }
    
    
        /**
         * 我的频道条目的点击事件
         *
         * @param myHolder
         * @param parent
         * @param v
         */
        private void clickMyChannelItem(MyViewHolder myHolder, ViewGroup parent, View v) {
            int position = myHolder.getAdapterPosition();
            if (isEditMode) {
                if (position != 1) {
                    RecyclerView recyclerView = ((RecyclerView) parent);
                    View targetView = recyclerView.getLayoutManager().findViewByPosition(mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER);
                    View currentView = recyclerView.getLayoutManager().findViewByPosition(position);
                    // 如果targetView不在屏幕内,则indexOfChild为-1
                    // 此时不需要添加动画,因为此时notifyItemMoved自带一个向目标移动的动画
                    // 如果在屏幕内,则添加一个位移动画
                    if (recyclerView.indexOfChild(targetView) >= 0) {
                        Logger.e("从我的频道到其他频道,用到了自定义动画");
                        int targetX, targetY;
    
                        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
                        int spanCount = ((GridLayoutManager) manager).getSpanCount();
    
                        // 移动后 高度将变化 (我的频道Grid 最后一个item在新的一行第一个)
                        if ((mMyChannelItems.size() - COUNT_PRE_MY_HEADER) % spanCount == 0) {
                            View preTargetView = recyclerView.getLayoutManager().findViewByPosition(mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER - 1);
                            targetX = preTargetView.getLeft();
                            targetY = preTargetView.getTop();
                        } else {
                            targetX = targetView.getLeft();
                            targetY = targetView.getTop();
                        }
    
                        moveMyToOther(myHolder);
                        startAnimation(recyclerView, currentView, targetX, targetY);
    
                    } else {
                        moveMyToOther(myHolder);
                    }
                }
    
            } else {
                if (mChannelItemClickListener != null) {
                    mChannelItemClickListener.onItemClick(v, position - COUNT_PRE_MY_HEADER);
                }
            }
        }
    
        public List<TagBean> getmOtherChannelItems() {
            return mOtherChannelItems;
        }
    }
    

    adpater的代码可能比较多,但逻辑也非常简单,从代码中我们可以发现实现了MyViewHolder.java实现了OnDragVHListener接口,ClassifyAdapter实现了OnItemMoveListener接口,这些调用逻辑清楚了,其实我们就比较好理解了。

    完整demo地址

    相关文章

      网友评论

          本文标题:RecyclerView-->拖拽排序,点击删除

          本文链接:https://www.haomeiwen.com/subject/ljobxftx.html