一、小红书效果
上面三个图是小红书发布动态的时候选择好图片后,长按图片进行排序的效果。长按后,选择的图片浮起,随手指左右移动,靠近左右边缘的时候,整体的条目可以左右滚动,再将手指选择的图片发到合适的位置。
二、改进效果
1.首先是可以上下左右拖动,解决了,只左右滚动,在选择后图片放大导致顶部被切割的问题。
2.当图片满足9个的时候将最后位置的+号隐藏,小于9个的时候显示+号。小红书并未做此处理。
3.加入了仿微信拖动到某处删除图片的功能
三、实现方案
采用recyclerView+ItemTouchHelper
1.首先创建adapter,定义两种类型的type,一种是pic,一种是+号类型。可设置maxCount,比如最多设置9张图片。
+号始终在最后一位。这样设计,当加入的图片等于maxCount的时候,+号就自动隐藏掉了。
2.拖动实现
定义ItemTouchHelper.Callback
定义可上下左右四个方向拖动,同时标注+号类型不可拖动。
定义当不同类型、+号类型,图片不足2个的时候,不可发生交换。
设置长按可拖拽
3.拖动删除逻辑
布局文件定义如下
关键代码为clipChildren = "false" 设置在recyclerview的父布局上,可以使item拖动的时候显示超出recyclerview,这样recyclerview不需要全屏,高度只需要按需设置即可。
同时定义一个拖动到该位置删除Item的view区域,如上图id为delete_area
回到 ItemTouchHelper.Callback 定义listener用于判断,drag开始,结束,和是否item进入删除区域的回调
onSelectedChanged函数用于判断选择的状态
不在闲置状态(即开始拖动状态)下,将被选择的item放大mScale倍,同时通知回调,并记录当前临时的holder。
回到闲置状态的时候(拖动后抬手动作),这个时候回调回来的holder是null,所以需要在拖动开始的时候记录临时变量。用来在拖动到删除区域做删除作用。
clearView是在拖动结束并且item归位动画结束后触发,所以用来将放大的view还原。
当item被拖动的时候会不断触发onChildDraw函数,所以在此函数中判断拖动的item是否和删除区域发生重合,
tem和delArea都用此方法获取在窗口中的位置。
由于有item拖动的时候会放大,所以实际计算的时候需要按照放大的item计算
然后通过上下左右的的坐标判断是否发生重叠。这样可以适应任何位置和大小的删除区域,如下图:
回到onSelectedChanged方法,判断抬手动作(闲置状态)的时候,判断是否发生重叠,如果重叠则进行删除逻辑。
注意此时删除由于会执行归位动画,item被remove了,但是归位动画又执行了,所以最终item会被归位到原处,后一个item会顶上来发生重合,并且该归位的item的index为-1,此时若点击该归位的item发生崩溃,因为index异常。所以需要将归位动画取消。
如上图,该函数发生在抬手后,即将执行动画之前会获取此函数返回的动画时间,所以设置当发生重叠要删除的时候,动画时间为0就不会执行动画了。
此时问题又来了,动画不执行了,item会立即回到原位并执行消失动画,此时item会先显示出来再消失,所以需要先隐藏掉该item
隐藏掉item,但是holder的view是复用的,会导致后面被复用的holder也隐藏掉。所以removeItemFromDrag做一些处理
为了使删除动画不受影响,不可以使用notifyDataSetChanged,同时为了避免全部刷新导致闪烁,所以使用notifyItemRangeChanged的payload的方式局部刷新。将itemview设置为显示即可。
4.使用方法
设置,itemHeight,setProportion设置宽高比例,设置水平方向的layoutmanager
设置,itemHeight,setProportion设置宽高比例,设置水平方向的layoutmanager
设置callback,传入adapter和删除区域view,设置选中放大比例setScale,attach到recyclerview
四、开源代码
组件demo已上传到github,传送门:https://github.com/DrJia/PicMgrDemo