您的位置:首页 > 移动开发 > Android开发

Android学习笔记030之RecyclerView和CardView实现拖拽和滑动

2016-07-18 11:39 399 查看

Android学习笔记030之RecyclerView和CardView实现拖拽和滑动

  在上一篇中,我们介绍了SwiperefreshLayout、RecyclerView和CardView,还用着三个控件组合实现了一些效果,下拉刷新也不在需要用第三方的框架,实现的效果也比较符合Google的MD设计,这一节,我们使用RecyclerView和CardView组合实现拖拽和滑动删除的效果。

RecyclerView实现拖拽和滑动删除非常简单,只需要实现下面的三句代码:

//关联RecyclerView
ItemTouchHelper.Callback callback=new ItemTouchCallback(dragAdapter);
ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(rv_drag_list);


  我们看到,要实现拖拽和滑动删除需要实现一个适配器和一个回调接口。其中,这个回调接口需要我们自己去实现,重点就是实现的这个回调接口,下面我们具体介绍一下这个自定义的回调接口:

我们自定义一个类,实现ItemTouchHelper.Callback这个接口,先看一下具体的自定义回调接口的源码

package com.example.newapidemo.common;

import android.graphics.Canvas;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

/**
* Created by Devin on 2016/7/15.
*/
public class ItemTouchCallback extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private ItemTouchAdapter itemTouchAdapter;

public ItemTouchCallback(ItemTouchAdapter itemTouchAdapter) {
this.itemTouchAdapter = itemTouchAdapter;
}

/**
* 指定可以支持的拖放和滑动的方向
* List类型的RecyclerView,拖拽只有UP、DOWN
* Grid类型的则有UP、DOWN、LEFT、RIGHT四个方向
* <p/>
* dragFlags 是拖拽标志,swipeFlags是滑动标志,在Grid中把swipeFlags设置为0,表示不处理滑动操作。
*
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//判断recyclerView传入的LayoutManager是不是GridLayoutManager
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
//Grid的拖拽方向,上、下、左、右
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
//设置为0,表示不支持滑动
final int swipeFlags = 0;
//创建拖拽或者滑动标志的快速方式
return makeMovementFlags(dragFlags, swipeFlags);
} else {
//List类型的拖拽方向,上或者下
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//List类型支持滑动,左或者右
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
//创建拖拽或者滑动标志的快速方式
return makeMovementFlags(dragFlags, swipeFlags);
}
}

/**
* 告诉ItemTouchHelper是否需要RecyclerView支持长按拖拽,返回true是支持,false是不支持
*
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}

/**
* 告诉ItemTouchHelper是否需要RecyclerView支持滑动,返回true是支持,false是不支持
*
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}

/**
* 当拖拽开始的时候调用
*
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//拖拽的时候改变一下选中Item的颜色
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder instanceof ItemTouchHelperViewHolder) {
//让ViewHolder知道Item开始选中
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
//回调ItemTouchHelperVIewHolder的方法
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}

/**
* 当拖拽结束的时候调用
*
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
if (viewHolder instanceof ItemTouchHelperViewHolder) {
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
//Item移动完成之后的回调
itemViewHolder.onItemClear();
}
}

/**
* 当ItemTouchHelper要拖动的Item从原来位置拖动到新的位置的时候调用
* 当我们拖拽的时候调用这个方法
*
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//如果两个item不是一个类型的,我们让他不可以拖拽
if (viewHolder.getItemViewType() != target.getItemViewType()) {
return false;
}

//得到拖动ViewHolder的position
int fromPosition = viewHolder.getAdapterPosition();
//得到目标ViewHolder的position
int toPosition = target.getAdapterPosition();
itemTouchAdapter.onItemMove(fromPosition, toPosition);

return true;
}

/**
* 当ViewHolder滑动的时候调用
* 当滑动Item的时候调用此方法
*
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
itemTouchAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}

/**
* 由 ItemTouchHelper 在 RecyclerView 的 onDraw方法中回调调用
*
* @param c
* @param recyclerView
* @param viewHolder
* @param dX
* @param dY
* @param actionState
* @param isCurrentlyActive
*/
@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);
}
}
}


除了这个回调接口之外,我们还定义了几个接口

package com.example.newapidemo.common;
/**
* Created by Devin on 2016/7/15.
*/
public interface ItemTouchHelperViewHolder {
/**
* 当Item开始拖拽或者滑动的时候调用
*/
void onItemSelected();

/**
* 当Item完成拖拽或者滑动的时候调用
*/
void onItemClear();
}


这个接口是实现拖拽或者滑动完成或者正在拖拽或滑动的回调,我们可以定义拖拽或者滑动时候一些样式或者其他想要实现的效果。

还有一个就是适配器需要实现的接口:

package com.example.newapidemo.common;

/**
* Created by Devin on 2016/7/15.
*/
public interface ItemTouchAdapter {
/**
* Item已经移动的足够远的时候调用
*
* @param fromPosition
* @param toPosition
* @return
*/
boolean onItemMove(int fromPosition, int toPosition);

/**
* 当Item滑动取消的时候调用
*
* @param position
*/
void onItemDismiss(int position);
}


这个接口就不在描述很多了。

在我们实现那个回调接口的时候,就有做判断,当RecyclerView时List列表样式的时候就可以实现滑动删除和拖拽两种效果,但是是Grid网格效果的时候就只能拖拽。下面我们看一下适配器的实现:

package com.example.newapidemo.adapter;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.newapidemo.R;
import com.example.newapidemo.common.ItemTouchAdapter;
import com.example.newapidemo.common.ItemTouchHelperViewHolder;
import com.example.newapidemo.domain.RVTest;

import java.util.Collections;
import java.util.List;

/**
* Created by Devin on 2016/7/18.
*/
public class RVDragAdapter extends RecyclerView.Adapter<RVDragAdapter.RVDragViewHolder> implements ItemTouchAdapter {
private Context mContext;
private List<RVTest> datas;

public RVDragAdapter(Context mContext, List<RVTest> datas) {
this.mContext = mContext;
this.datas = datas;
}

@Override
public RVDragViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_fragment_list, parent, false);
return new RVDragViewHolder(view);
}

@Override
public void onBindViewHolder(RVDragViewHolder holder, int position) {
holder.tv_drag_list.setText(datas.get(position).getContent());
}

@Override
public int getItemCount() {
return datas.size();
}

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(datas, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return true;
}

@Override
public void onItemDismiss(int position) {
datas.remove(position);
notifyItemRemoved(position);
}

public static class RVDragViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
TextView tv_drag_list;
CardView cv_drag;

public RVDragViewHolder(View itemView) {
super(itemView);
tv_drag_list
= (TextView) itemView.findViewById(R.id.tv_drag_list);
cv_drag = (CardView) itemView.findViewById(R.id.cv_drag);
}

//设置item选中拖拽的时候调用
@Override
public void onItemSelected() {
itemView.setBackgroundColor(Color.GRAY);
cv_drag.setRadius(R.dimen.cv_drag);
}

//当Item拖拽完成时候调用
@Override
public void onItemClear() {
itemView.setBackgroundColor(Color.WHITE);
cv_drag.setRadius(R.dimen.cv_drag);
}
}
}


适配器的实现跟其他实现RecyclerView的适配器差不多,但是必须要实现ItemTouchAdapter这个接口,ViewHolder也需要实现ItemTouchHelperViewHolder这个接口,这是我们自定义的接口,里面提供我们的几个回调,可以更改一些设置,在这里就简单的实现拖拽之后Item的一些简单样式。

最后是Fragment的实现:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rvlist, container, false);
rv_drag_list = (RecyclerView) view.findViewById(R.id.rv_drag_list);
initData();
rv_drag_list.setLayoutManager(new LinearLayoutManager(getContext()));
dragAdapter = new RVDragAdapter(getContext(), datas);
rv_drag_list.setAdapter(dragAdapter);
//关联RecyclerView
ItemTouchHelper.Callback callback=new ItemTouchCallback(dragAdapter);
ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(rv_drag_list);
return view;
}

private void initData() {
if (datas == null) {
datas = new ArrayList<>();
}
for (int i = 0; i < 20; i++) {
datas.add(new RVTest(i, "测试数据第 " + (i + 1) + " 条"));
}

}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rvgrid, container, false);
rv_drag_grid = (RecyclerView) view.findViewById(R.id.rv_drag_grid);
rv_drag_grid.setLayoutManager(new GridLayoutManager(getContext(), 2));
initData();
adapter=new RVDragAdapter(getContext(),datas);
rv_drag_grid.setAdapter(adapter);
ItemTouchCallback callback=new ItemTouchCallback(adapter);
ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(rv_drag_grid);
return view;
}
private void initData() {
if (datas == null) {
datas = new ArrayList<>();
}
for (int i = 0; i < 40; i++) {
datas.add(new RVTest(i, "第 " + (i + 1) + " 条数据"));
}

}


这里都是很简单的实现,下面我们看一下效果图:



这只是很简单的实现,在实际项目中可以按自己的需求做扩展。下面是Demo的源码

猛戳下载Demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: