效果演示
需求介绍
根据数据类型动态的改变每个item可操作状态,实现某些类型的item不响应长按拖拽
相信大家对于RecyclerView的长按拖拽并不陌生,通常我们会使用官方自带的ItemTouchHelper实现 通常来说只需要重写ItemTouchHelper.Callback的对应方法就可以实现一个简单的拖拽,但是对于某些类型Item不允许拖拽滑动的情况实现起来可能会比较麻烦。
具体实现
public class DefaultItemTouchHelperCallback extends ItemTouchHelper.Callback {
private OnItemTouchCallbackListener l;
//当前item可拖拽状态
private boolean currentPositionLongPressEnabled = true;
//整个列表的可操作状态 (总开关)
private boolean isLongPressEnabled;
private boolean isItemSwipeEnabled;
public DefaultItemTouchHelperCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) {
if (onItemTouchCallbackListener == null) {
throw new NullPointerException("OnItemTouchCallbackListener is null");
}
this.l = onItemTouchCallbackListener;
isLongPressEnabled = l.isLongPressDragEnabled();
isItemSwipeEnabled = l.isItemViewSwipeEnabled();
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int position = viewHolder.getAdapterPosition();
if (isLongPressEnabled)
currentPositionLongPressEnabled = l.currentPositionLongPressEnabled(position);
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {// GridLayoutManager
// flag如果值是0,相当于这个功能被关闭
int dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlag = 0;
// create make
return makeMovementFlags(dragFlag, swipeFlag);
} else if (layoutManager instanceof LinearLayoutManager) {// linearLayoutManager
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
int orientation = linearLayoutManager.getOrientation();
int dragFlag = 0;
int swipeFlag = 0;
// 为了方便理解,相当于分为横着的ListView和竖着的ListView
if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是横向的布局
swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是竖向的布局,相当于ListView
dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlag, swipeFlag);
}
return 0;
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int targetPosition = target.getAdapterPosition();
//如果fromPosition or targetPosition不可操作则直接返回false 不进行数据交换回调
return l.currentPositionLongPressEnabled(fromPosition)
&& l.currentPositionLongPressEnabled(targetPosition)
&& l.onMove(fromPosition, targetPosition);
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
l.onSwiped(viewHolder.getAdapterPosition());
}
@Override
public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
l.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
}
@Override
public boolean isLongPressDragEnabled() {
return isLongPressEnabled && currentPositionLongPressEnabled;
}
@Override
public boolean isItemViewSwipeEnabled() {
return isItemSwipeEnabled;
}
public interface OnItemTouchCallbackListener {
/**
* @param position 当前位置是否可长按拖拽
* @return 默认true 可拖拽
*/
default boolean currentPositionLongPressEnabled(int position) {
return true;
}
/**
* 所有item是否可拖拽
*
* @return 默认true 可拖拽
*/
default boolean isLongPressDragEnabled() {
return true;
}
/**
* 所有item是否可滑动删除
*
* @return 默认true 可删除
*/
default boolean isItemViewSwipeEnabled() {
return true;
}
/**
* @param position 滑动删除后位置
*/
default void onSwiped(int position) {
}
/**
* @param fromPosition 开始位置
* @param targetPosition 结束位置
* @return 是否处理
*/
boolean onMove(int fromPosition, int targetPosition);
default void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
}
}
}
复制代码
getMovementFlags():这个方法大家应该都比较了解了 在用户交互的时候返回当前item可滑动拖拽的方向参数 内部进行了简单的实现,根据不同的Manager LinearLayoutManager或GridLayoutManager进行了默认的方向设置
int position = viewHolder.getAdapterPosition();
if (isLongPressEnabled)
currentPositionLongPressEnabled = l.currentPositionLongPressEnabled(position);
复制代码
这部分代码就是主要的控制当前Item可操作的关键部分了,我们把对应位置传给接口实例具体这个item是否可拖拽只需要实现对应方法即可
onMove():这个方法通常在移动的时候替换对应的数据并刷新View
int fromPosition = viewHolder.getAdapterPosition();
int targetPosition = target.getAdapterPosition();
//如果fromPosition or targetPosition不可操作则直接返回false 不进行数据交换回调
return l.currentPositionLongPressEnabled(fromPosition)
&& l.currentPositionLongPressEnabled(targetPosition)
&& l.onMove(fromPosition, targetPosition);
复制代码
获取开始和目标的位置,根据接口实现判断是否可操作,如果2个position中有1个不可操作(不可移动) 那么此次拖拽就不应该交换位置,既没有回调onMove
@Override
public boolean isLongPressDragEnabled() {
return isLongPressEnabled && currentPositionLongPressEnabled;
}
@Override
public boolean isItemViewSwipeEnabled() {
return isItemSwipeEnabled ;
}
复制代码
因为ItemTouchHelper内部事件监听每次都会调用对应的Enabled方法 此处使用总开关和当前item的开关进行控制
OnItemTouchCallbackListener: 接口部分提供了对应的总开关和item开关,开关都默认返回了true开启状态。对于不需要的功能, 重写返回false即可。
效果演示的callback代码
private void initItemTouchHelper() {
DefaultItemTouchHelperCallback callback = new DefaultItemTouchHelperCallback(new DefaultItemTouchHelperCallback.OnItemTouchCallbackListener() {
@Override
public boolean onMove(int fromPosition, int targetPosition) {
List<PictureDraftBean.PicturesBean> imagePaths = adapter.datas;
//替换数据
Collections.swap(imagePaths, fromPosition, targetPosition);
//刷新
adapter.notifyItemMoved(fromPosition, targetPosition);
return true;
}
@Override
public boolean currentPositionLongPressEnabled(int position) {
//最后一个item是添加图片
return position != adapter.datas.size();
}
复制代码
第一次写文章,如果错误和疑问请指出。:)