RecyclerView ItemTouchHelper 踩坑之旅
要实现的功能:
- recyclerview item适配器不同类型的Item addHeaderView
- item headerview 不可以拖动交换位置
动手操作前先过一边原理 :站在大神的肩膀上看世界
谷歌大大这么说:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
This class is designed to work with any LayoutManager but for certain situations, it can be optimized for your custom LayoutManager by extending methods in the ItemTouchHelper.Callback class or implementing ItemTouchHelper.ViewDropHandler interface in your LayoutManager.
- RecylcerView Item拖动排序 滑动删除 依靠android.support.v7.widget.helper.ItemTouchHelper类
- 自定义ItemTouchHelper.callBack 继承 getMoventFlags\onMove\onSwiped 方法
谷歌大大这么说
This class is the contract between ItemTouchHelper and your application. It lets you control which touch behaviors are enabled per each ViewHolder and also receive callbacks when user performs these actions.
To control which actions user can take on each view, you should override getMovementFlags(RecyclerView, ViewHolder) and return appropriate set of direction flags. (LEFT, RIGHT, START, END, UP, DOWN). You can use makeMovementFlags(int, int) to easily construct it. Alternatively, you can use ItemTouchHelper.SimpleCallback.
If user drags an item, ItemTouchHelper will call onMove(recyclerView, dragged, target). Upon receiving this callback, you should move the item from the old position (dragged.getAdapterPosition()) to new position (target.getAdapterPosition()) in your adapter and also call notifyItemMoved(int, int). To control where a View can be dropped, you can override canDropOver(RecyclerView, ViewHolder, ViewHolder). When a dragging View overlaps multiple other views, Callback chooses the closest View with which dragged View might have changed positions. Although this approach works for many use cases, if you have a custom LayoutManager, you can override chooseDropTarget(ViewHolder, java.util.List, int, int) to select a custom drop target.
When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls onSwiped(ViewHolder, int). At this point, you should update your adapter (e.g. remove the item) and call related Adapter#notify event.
public class MyRecyclerViewTouchCallBack extends ItemTouchHelper.Callback {
private ItemTouchListencer mListencer;
public MyRecyclerViewTouchCallBack(ItemTouchListencer listencer) {
mListencer = listencer;
}
@Override
public boolean isLongPressDragEnabled() {
return super.isLongPressDragEnabled();
}
@Override
public boolean isItemViewSwipeEnabled() {
return super.isItemViewSwipeEnabled();
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
/*dragFlags--拖动标志*/
/*swipeFlags--滑动标志 GridLayoutManager滑动删除关闭*/
if (layoutManager instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
} else if (layoutManager instanceof LinearLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int startIndex = viewHolder.getAdapterPosition();
int endIndex = target.getAdapterPosition();
if (mListencer != null) {
mListencer.itemMove(startIndex, endIndex);
}
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
if (mListencer != null) {
mListencer.itemSwipe(direction);
}
}
}
控制器 RecylerViewAdapter
public class ItemTouchRecyclerViewAdapter extends RecyclerView.Adapter implements ItemTouchListencer {
private static final int TYPE_HEADER_VIEW = 0;
private static final int TYPE_CONTENT = 1;
private ArrayList mStrings;
private View mHeaderView;
public ItemTouchRecyclerViewAdapter(ArrayList strings) {
mStrings = strings;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER_VIEW) {
View view = View.inflate(parent.getContext(), R.layout.heander_view_item, null);
return new HeaderViewHolder(view);
} else if (viewType == TYPE_CONTENT) {
View view = View.inflate(parent.getContext(), R.layout.gridview_item, null);
return new GridViewHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof GridViewHolder) {
GridViewHolder gridViewHolder = (GridViewHolder) holder;
String str = mStrings.get(position - 1);
gridViewHolder.mTxt.setText(str);
}else if(holder instanceof HeaderViewHolder){
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
}
}
@Override
public int getItemCount() {
// return mHeaderView != null ? mStrings.size() + 1 : mStrings.size();
return mStrings.size();
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER_VIEW;
} else {
return TYPE_CONTENT;
}
}
/**
* 拖动回调接口
*
* @param startIndex --开始位置
* @param endIndex --交换结束位置
*/
@Override
public void itemMove(int startIndex, int endIndex) {
if (startIndex == 0 || endIndex == 0) {
return;
}
Collections.swap(mStrings, startIndex, endIndex);
notifyItemMoved(startIndex, endIndex);
}
/**
* 滑动删除
*
* @param delIndex
*/
@Override
public void itemSwipe(int delIndex) {
}
}
调用初始化
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.left = 2;
outRect.top = 2;
outRect.bottom = 2;
}
});
final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return position == 0 ? gridLayoutManager.getSpanCount() : 1;
}
});
mRecyclerView.setLayoutManager(gridLayoutManager);
ArrayList mStrings = new ArrayList<>();
for (int i = 0; i < 18; i++) {
mStrings.add("item "+i);
}
ItemTouchRecyclerViewAdapter adapter = new ItemTouchRecyclerViewAdapter(mStrings);
mRecyclerView.setAdapter(adapter);
MyRecyclerViewTouchCallBack callBack= new MyRecyclerViewTouchCallBack(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callBack);
touchHelper.attachToRecyclerView(mRecyclerView);
}
}