第一次接触RecyclerView你一定被它强大而神奇的功能所吸引,它可以实现ListView、GridView、瀑布流方式和水平列表方式,其自带删除和添加item的动画,甚至简简单单就可以实现item拖拽和滑动删除,其强大的功能往往让我们叹为观止。 今天我们一起玩RecyclerView。 本来录制好视频了,由于我用了Markdown版本来编写,Markdown不能插入视频,所以只能给大家看一张效果图了

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.lwj.uiproject.RecyclerActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="horizontal">
<Button
android:id="@+id/layout_vertical"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="vertical"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_horizontal"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="horizontal"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_grid"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="grid"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_Staggered"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="Staggered"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="horizontal">
<Button
android:id="@+id/layout_add"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="add"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_remove"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="remove"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#ffededed"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview_for2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
接下来看主页面文件内容,即RecyclerActivity
public class RecyclerActivity extends BaseActivity {
private RecyclerView mRecyclerview;
private RecyclerView2Aadapter mAdapter;
private List<String> mDatas = new ArrayList<>();
private Button vertical,horizontal,grid,staggered,add,remove;
private ItemTouchHelper mItemTouchHelper;//实现item滑动
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
getDatas();
initView();
initListener();
}
private void initView() {
grid = (Button)this.findViewById(R.id.layout_grid);
horizontal = (Button)this.findViewById(R.id.layout_horizontal);
vertical = (Button)this.findViewById(R.id.layout_vertical);
staggered = (Button)this.findViewById(R.id.layout_Staggered);
add = (Button)this.findViewById(R.id.layout_add);
remove = (Button)this.findViewById(R.id.layout_remove);
mRecyclerview = (RecyclerView)this.findViewById(R.id.recyclerview_for2);
//设置点击事件
grid.setOnClickListener(mOnclickLitener);
horizontal.setOnClickListener(mOnclickLitener);
vertical.setOnClickListener(mOnclickLitener);
staggered.setOnClickListener(mOnclickLitener);
add.setOnClickListener(mOnclickLitener);
remove.setOnClickListener(mOnclickLitener);
//设置layout显示样式
mRecyclerview.setLayoutManager(new GridLayoutManager(this,3));
mAdapter = new RecyclerView2Aadapter(RecyclerActivity.this,mDatas);
mRecyclerview.setAdapter(mAdapter);
ItemTouchHelperCallBack back = new ItemTouchHelperCallBack(mAdapter);
mItemTouchHelper = new ItemTouchHelper(back);
mItemTouchHelper.attachToRecyclerView(mRecyclerview);//关联Recyclerview
}
/**
* 点击事件监听器
*/
private View.OnClickListener mOnclickLitener = new View.OnClickListener() {
@Override
public void onClick(View view) {
mAdapter.setStagger(false);
switch (view.getId()){
case R.id.layout_grid:
mRecyclerview.setLayoutManager(new GridLayoutManager(RecyclerActivity.this,3));
break;
case R.id.layout_horizontal:
mRecyclerview.setLayoutManager(new LinearLayoutManager(RecyclerActivity.this,LinearLayoutManager.HORIZONTAL,true));
break;
case R.id.layout_Staggered:
mAdapter.setStagger(true);
mRecyclerview.setLayoutManager(new StaggeredGridLayoutManager(4,LinearLayoutManager.VERTICAL));
break;
case R.id.layout_vertical:
mRecyclerview.setLayoutManager(new LinearLayoutManager(RecyclerActivity.this,LinearLayoutManager.VERTICAL,true));
break;
case R.id.layout_add:
mAdapter.addData(20);
break;
case R.id.layout_remove:
mAdapter.removeData(21);
break;
default:
break;
}
}
};
//获取数据
public void getDatas() {
for (int i = 0; i < 100; i++) {
String data = "Itme "+i;
mDatas.add(data);
}
}
private void initListener() {
//通过回调来设置item的点击事件
mAdapter.setOnItemOnclickListener(new RecyclerView2Aadapter.OnItemOnclickListener() {
@Override
public void onclick(String str) {
Toast.makeText(RecyclerActivity.this,str,Toast.LENGTH_SHORT).show();
}
});
//设置拖拽或者滑动的开始
mAdapter.setOnStartDragListener(new ItemTouchHelperCallBack.OnStartDragListener() {
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
});
}
}
由于RecyclerView列表的item不会像ListView一样具有item点击事件监听器,所以我们需要自己设置一个点击事件的监听器回调,这样子就可以在activity中处理item的点击事件了。这里还通过button的点击给用户展示不一样的列表,包括像ListView、GridView、水平列表和瀑布流。RecyclerView自带拖拽和滑动删除的功能,这里会通过ItemTouchHelper设置它的CallBack,然后关联上RecyclerView即可实现这功能。
下面我们看adapter文件RecyclerView2Aadapter.java的内容
public class RecyclerView2Aadapter extends RecyclerView.Adapter implements ItemTouchHelperCallBack.ItemTouchHelperAdapterListener {
private List<String> mDatas;
private Context mContext;
private OnItemOnclickListener mOnItemOnclickListener;
private List<Integer> heights;
private boolean isStagger = false;
private ItemTouchHelperCallBack.OnStartDragListener mDragStartListener;
public RecyclerView2Aadapter(Context mContext, List<String> mDatas) {
this.mDatas = mDatas;
this.mContext = mContext;
heights = new ArrayList<Integer>();
if (mDatas != null && mDatas.size() > 0) {
for (int i = 0; i < mDatas.size(); i++) {
heights.add((int) Math.max(200, Math.random() * 550));
}
}
}
public void setOnStartDragListener(ItemTouchHelperCallBack.OnStartDragListener l){
this.mDragStartListener = l;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);
return new RecyclerViewItemLayout(view);
}
//绑定数据
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
RecyclerViewItemLayout item = (RecyclerViewItemLayout) holder;
int height = heights.get(position);
String str = mDatas.get(position);
setData(item, str, height);
// item.mBtn.setOnTouchListener(new OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
// mDragStartListener.onStartDrag(holder);
// }
// return false;
// }
// });
}
@Override
public int getItemCount() {
if (mDatas != null && mDatas.size() > 0) {
return mDatas.size();
}
return 0;
}
/**
* 设置数据
*
* @param item
* @param str
* @param height
*/
public void setData(RecyclerViewItemLayout item, String str, int height) {
if (TextUtils.isEmpty(str) || str == item.mTagStr) {
return;
} else {
item.mTagStr = str;
item.mBtn.setText(item.mTagStr);
if (isStagger) {
LinearLayout.LayoutParams p = (LinearLayout.LayoutParams) item.mBtn.getLayoutParams();
p.height = height;
item.mBtn.setLayoutParams(p);
} else {
LinearLayout.LayoutParams p = (LinearLayout.LayoutParams) item.mBtn.getLayoutParams();
p.height = LinearLayout.LayoutParams.WRAP_CONTENT;
item.mBtn.setLayoutParams(p);
}
}
}
private class RecyclerViewItemLayout extends RecyclerView.ViewHolder implements ItemTouchHelperCallBack.ItemTouchHelperViewHolder{
private String mTagStr;
private Button mBtn;
public RecyclerViewItemLayout(LinearLayout view) {
super(view);
mBtn = (Button) view.findViewById(R.id.item_btn);
mBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mOnItemOnclickListener != null) {
mOnItemOnclickListener.onclick(mTagStr);
}
}
});
}
@Override
public void onItemSelected() {
itemView.setBackgroundColor(0xffadadad);
Animation animation=new ScaleAnimation(0,1.05f,0,1.05f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);//放大5%,即1.05倍,中点为缩放中心
animation.setFillAfter(true);
itemView.startAnimation(animation);
itemView.bringToFront();
itemView.setAlpha(1);//不透明
}
@Override
public void onItemClear() {
itemView.setBackgroundColor(0xffededed);
itemView.clearAnimation();//清除动画
}
}
/**
* 拖拽实现
* @param fromPosition
* @param toPosition
* @return
*/
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(mDatas, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return true;
}
/**
* 滑动删除
* @param position
*/
@Override
public void onItemDismiss(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
public interface OnItemOnclickListener {
void onclick(String str);
}
/**
* 设置item点击事件的回调
* @param listener
*/
public void setOnItemOnclickListener(OnItemOnclickListener listener) {
this.mOnItemOnclickListener = listener;
}
public void setStagger(boolean stagger) {
isStagger = stagger;
}
/**
* 往列表添加一个item
* @param position
*/
public void addData(int position) {
mDatas.add(position, "additem" + position);
notifyItemInserted(position);
}
/**
* 删除列表的一个item
* @param position
*/
public void removeData(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/item_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="hello" />
</LinearLayout>
RecyclerView的adapter需要实现RecyclerView.Adapter,默认需要重写里面的getItemCount、onBindViewHolder、onCreateViewHolder这三个方法,这里需要ItemTouchHelperAdapterListener接口,实现item拖拽和滑动的回调。RecyclerView具有的adapter好处就是具有解绑特性,为我们区分了item界面创建和数据绑定的方法,而不像ListView一样都集中在getView方法中处理。RecyclerView.ViewHolder本身已经具有holder的缓存。所以我们不用做特殊处理,大大提高了开发效率。 这里创建的holder(RecyclerViewItemLayout)除了要继承ViewHolder之外还要实现ItemTouchHelperViewHolder这个接口,这里接口主要通过回调来实现item拖拽和滑动,当用户按住(选择)item时和完成操作时item所做的一些效果处理。
接下来我们看看实现拖拽和滑动的ItemTouchHelper.Callback
public class ItemTouchHelperCallBack extends ItemTouchHelper.Callback{
private static final float ALPHA = 1.0f;
private ItemTouchHelperAdapterListener mItemTouchHelperAdapterListener;
public ItemTouchHelperCallBack(ItemTouchHelperAdapterListener l){
this.mItemTouchHelperAdapterListener = l;
}
/**
* 是否支持长按
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 是否支持滑动
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
/**
* 滑动方向
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if(recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager)
{
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
else
{
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
/**
* 拖拽完成
* @param recyclerView
* @param viewHolder
* @param target
* @return
* Called when ItemTouchHelper wants to move the dragged item from its old position to the new position.
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if(viewHolder.getItemViewType() != target.getItemViewType())
{
return false;
}
if (mItemTouchHelperAdapterListener != null){
mItemTouchHelperAdapterListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
}
return true;
}
/**
* 左右滑动删除
* Called when a ViewHolder is swiped by the user.
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
if (mItemTouchHelperAdapterListener != null){
mItemTouchHelperAdapterListener.onItemDismiss(viewHolder.getAdapterPosition());
}
}
/**
* 拖拽的时候给item添加一个背景色
*
* @param viewHolder
* @param actionState
* Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE)
{
if(viewHolder instanceof ItemTouchHelperViewHolder)
{
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 在这个方法实现交互规则
* @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 - 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);
}
}
/**
* Called by the ItemTouchHelper
* when the user interaction with an element is over
* 操作完成并且其动画也结束后会调用该方法
* 一般在该方法内恢复ItemView的初始状态
* and it also completed its animation.
* @param recyclerView
* @param viewHolder
*
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA);
if(viewHolder instanceof ItemTouchHelperViewHolder)
{
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;
itemViewHolder.onItemClear();
}
}
public interface ItemTouchHelperViewHolder
{
void onItemSelected();
void onItemClear();
}
public interface ItemTouchHelperAdapterListener
{
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
//当视图请求开始挪动是调用
public interface OnStartDragListener
{
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
}
这里主要是实现item拖拽和滑动的功能,以及一些设置。用户需要实现列表的item的滑动和拖拽功能就必须要重写Callback的抽象方法才能完成。
参考文章: 吴小龙同学.《Android ItemTouchHelper 实践》
有发现问题的可以留言,喜欢的点个赞。你的喜欢就是我分享的动力!!!