Android提供了ItemTouchHelper类,使得RecyclerView能够轻易地实现滑动和拖拽,此处我们要实现上下拖拽和侧滑删除。
① 创建ItemTouchHelper.Callback类
首先创建一个继承自ItemTouchHelper.Callback
的类,并重写以下方法:
getMovementFlags()
: 设置支持的拖拽和滑动的方向,此处我们支持的拖拽方向为上下,滑动方向为从左到右和从右到左,内部通过makeMovementFlags()
设置。onMove()
: 拖拽时回调。onSwiped()
: 滑动时回调。onSelectedChanged()
: 状态变化时回调,一共有三个状态,分别是ACTION_STATE_IDLE(空闲状态),ACTION_STATE_SWIPE(滑动状态),ACTION_STATE_DRAG(拖拽状态)。此方法中可以做一些状态变化时的处理,比如拖拽的时候修改背景色。clearView()**
: 用户交互结束**时回调。此方法可以做一些状态的清空,比如拖拽结束后还原背景色。isLongPressDragEnabled()
: 是否支持长按拖拽,默认为true。如果不想支持长按拖拽,则重写并返回false。
具体实现如下:
public class SimpleItemTouchCallback extends ItemTouchHelper.Callback {
private NormalAdapter mAdapter;
private List<ObjectModel> mData;
public SimpleItemTouchCallback(NormalAdapter adapter, List<ObjectModel> data){
mAdapter = adapter;
mData = data;
}
//设置支持的拖拽、滑动的方向
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN; //s上下拖拽
int swipeFlag = ItemTouchHelper.START | ItemTouchHelper.END; //左->右和右->左滑动
return makeMovementFlags(dragFlag,swipeFlag);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
Collections.swap(mData, from, to);
mAdapter.notifyItemMoved(from, to);
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int pos = viewHolder.getAdapterPosition();
mData.remove(pos);
mAdapter.notifyItemRemoved(pos);
}
//状态改变时回调
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
NormalAdapter.VH holder = (NormalAdapter.VH)viewHolder;
holder.itemView.setBackgroundColor(0xffbcbcbc); //设置拖拽和侧滑时的背景色
}
}
//拖拽或滑动完成之后调用,用来清除一些状态
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
NormalAdapter.VH holder = (NormalAdapter.VH)viewHolder;
holder.itemView.setBackgroundColor(0xffeeeeee); //背景色还原
}
}
② 设置ItemTouchHelper给RecyclerView
然后通过以下代码为RecyclerView设置该滑动、拖拽功能:
ItemTouchHelper helper = new ItemTouchHelper(new SimpleItemTouchCallback(adapter, data));
helper.attachToRecyclerView(recyclerview);
触摸拖拽
前面拖拽的触发方式只有长按,如果想支持触摸Item中的某个View实现拖拽,则核心方法为helper.startDrag(holder)
。首先定义接口:
interface OnStartDragListener{
void startDrag(RecyclerView.ViewHolder holder);
}
然后让Activity实现该接口:
public MainActivity extends Activity implements OnStartDragListener{
...
public void startDrag(RecyclerView.ViewHolder holder) {
mHelper.startDrag(holder);
}
}
如果要对ViewHolder的text对象支持触摸拖拽,则在Adapter中的onBindViewHolder()
中添加:
holder.text.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
mListener.startDrag(holder);
}
return false;
}
});
其中mListener是在创建Adapter时将实现OnStartDragListener接口的Activity对象作为参数传进来。
完整代码如下:
public class NormalAdapter extends RecyclerView.Adapter<NormalAdapter.VH>{
private List<ObjectModel> mDatas;
private OnStartDragListener mListener;
public NormalAdapter(List<ObjectModel> data, OnStartDragListener listener) {
this.mDatas = data;
mListener = listener;
}
@Override
public void onBindViewHolder(final VH holder, int position) {
ObjectModel model = mDatas.get(position);
holder.title.setText(model.title);
holder.number.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
mListener.startDrag(holder);
}
return false;
}
});
}
@Override
public int getItemCount() {
return mDatas.size();
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_3, parent, false);
return new VH(v);
}
public static class VH extends RecyclerView.ViewHolder{
public final TextView title;
public final ImageView number;
public VH(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
number = (ImageView) v.findViewById(R.id.icon);
}
}
}
public class Activity3 extends AppCompatActivity implements OnStartDragListener{
private RecyclerView mRv;
private NormalAdapter mAdapter;
private ItemTouchHelper mHelper;
private List<ObjectModel> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
mRv = (RecyclerView) findViewById(R.id.rv);
mRv.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new NormalAdapter(mData = initData(), this);
mRv.setAdapter(mAdapter);
mHelper = new ItemTouchHelper(new SimpleItemTouchCallback(mAdapter, mData));
mHelper.attachToRecyclerView(mRv);
}
public ArrayList<ObjectModel> initData(){
ArrayList<ObjectModel> models = new ArrayList<>();
String[] titles = getResources().getStringArray(R.array.title_array);
for(int i=0;i<titles.length;i++){
ObjectModel model = new ObjectModel();
model.number = i + 1;
model.title = titles[i];
models.add(model);
}
return models;
}
@Override
public void startDrag(RecyclerView.ViewHolder holder) {
mHelper.startDrag(holder);
}
}
interface OnStartDragListener{
void startDrag(RecyclerView.ViewHolder holder);
}