ItemTouchHelper.Callback实现仿朋友圈发布图片拖拽排序

项目需求需要类似发布朋友圈拖拽排序的功能,故此记录一下,感谢Android SDK的强大。

API链接:https://developer.android.com/reference/android/support/v7/widget/helper/ItemTouchHelper.Callback

效果视频如下:

网上有很多使用GirdView实现拖拽排序效果相对来说比较复杂,在保证效率和质量的情况下我这里选择使用RecycleView,官方提供了TiemTouchHelper来支持此效果的完成,它的出现本意是上下拖拽实现排序,左右拖拽实现删除(此处非瀑布流)。但是实现拖拽效果已经绰绰有余了。下面我们开始吧。

TiemTouchHelper:(官方解释)

此类是ItemTouchHelper与您的应用程序之间的契约。它允许您控制每个ViewHolder启用触摸行为,并在用户执行这些操作时接收回调。

要控制用户可以对每个视图执行哪些操作,您应该覆盖 getMovementFlags(RecyclerView, ViewHolder)并返回适当的方向标志集。(LEFTRIGHTSTARTEND, UPDOWN)。您可以使用 makeMovementFlags(int, int)它轻松构建它。或者,您可以使用 ItemTouchHelper.SimpleCallback

如果用户拖动item,ItemTouchHelper将调用 onMove(recyclerView, dragged, target)。收到此回调后,您应该将项目从旧位置(dragged.getAdapterPosition())移动到target.getAdapterPosition()适配器中的新位置()并调用notifyItemMoved(int, int)。要控制可以删除视图的位置,您可以覆盖 canDropOver(RecyclerView, ViewHolder, ViewHolder)。当拖动视图与多个其他视图重叠时,Callback会选择最近的视图,拖动的视图可能会更改位置。虽然此方法适用于许多用例,但如果您有自定义LayoutManager,则可以覆盖 chooseDropTarget(ViewHolder, java.util.List, int, int)以选择自定义放置目标。

滑动视图时,ItemTouchHelper会对其进行动画处理,直到它超出范围,然后调用 onSwiped(ViewHolder, int)。此时,您应该更新适配器(例如删除item)并调用相关的Adapter#notify事件。

自定义了Recycleview实现拖拽,更换位置有数据换位置然后刷新实现并非Recycleview自己实现,代码如下:

public class DragItemRecyclerView extends RecyclerView {
    private ItemTouchHelper itemTouchHelper;
    private DragAdapter dragAdapter;
    private float ALPHA_FULL = 1.0f;

    public DragItemRecyclerView(Context context) {
        super(context);
    }

    public DragItemRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DragItemRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);
        dragAdapter = (DragAdapter) adapter;
        init();
    }

    private void init() {
        this.getItemAnimator().setChangeDuration(0);
        if (itemTouchHelper == null) {
            itemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback());
            itemTouchHelper.attachToRecyclerView(this);
        }
    }

    public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
        int endPosition, startPosition;

        @Override
        public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
            if (dragAdapter.list != null && !TextUtils.isEmpty(dragAdapter.list.get(viewHolder.getAdapterPosition())) && dragAdapter.list.get(viewHolder.getAdapterPosition()).equals(CreateTopicActivity.ADD_IMAGE)) {
                return makeMovementFlags(0, 0);
            }
            if (dragAdapter.list != null && !TextUtils.isEmpty(dragAdapter.list.get(viewHolder.getAdapterPosition())) && !PhotoTools.isImageFile(dragAdapter.list.get(viewHolder.getAdapterPosition()))) {
                return makeMovementFlags(0, 0);
            }
            if (recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
                final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                //不需要滑动
                final int swipeFlags = 0;
                return makeMovementFlags(dragFlags, swipeFlags);
            } else {
                final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                return makeMovementFlags(dragFlags, swipeFlags);
            }
        }

        @Override
        public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
            if (viewHolder.getItemViewType() != target.getItemViewType()) {
                return false;
            }
            startPosition = viewHolder.getAdapterPosition();
            endPosition = target.getAdapterPosition();
            return dragAdapter.onItemMove(startPosition, endPosition);
        }

        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
            if (dragAdapter != null) {
                dragAdapter.notifyItemRangeChanged(Math.min(startPosition, endPosition), Math.abs(startPosition - endPosition) + 1);
            }
        }

        @Override
        public boolean canDropOver(RecyclerView recyclerView, ViewHolder current, ViewHolder target) {
            return true;
        }

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

        @Override
        public boolean isLongPressDragEnabled() {
            return true;
        }

        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
                //自定义滑动动画
                final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
                viewHolder.itemView.setAlpha(alpha);
                viewHolder.itemView.setTranslationX(dX);
            } else {
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }
        }
    }

    public interface ItemTouchHelperAdapter {
        //数据交换
        boolean onItemMove(int fromPosition, int toPosition);
    }
}

adapter相关代码,主要是onMore调起在adapter内方法,根据返回更换位置item的position更换数据位置然后notify,代码如下:

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        if (list.get(toPosition).equals(CreateTopicActivity.ADD_IMAGE))
            return false;
        if (!PhotoTools.isImageFile(list.get(toPosition)))
            return false;
        //交换位置
        Collections.swap(list, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

上述第一个if是判断是不是添加按钮,如果是不更换,需求默认添加按钮在最后。第二个if判断是否是视频,视频需求默认第一位也不可更换位置。

大家没有看错就这点代码实现了所有功能,如果大家还有什么问题欢迎留言。

测试阶段出现了数据混乱的问题,代码已做修正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值