Android开发之RecyclerView的交互动画(实现拖拽和删除)
程序员文章站
2022-05-04 19:53:48
...
做RecyclerView做相关的动画效果的时候,用的最多的是v7包下的ItemTouchHelper类,这个类很强大,如有兴趣的童鞋可以自行翻看源码,接下来我带领大家实现RecyclerView相关的交互动画。大家看下面的效果(拖拽和删除):
------------------------------------------华丽的分割线---------------------------------------------------------------------
实现原理:通过重写ItemTouchHelper类的callback回调方法,然后itemTouchHelper.attachToRecyclerView(mRecyclerView)来实现item的拖拽和删除。
------------------------------------------华丽的分割线---------------------------------------------------------------------
首先我们需要先定义一个接口
当拖拽的时候回调和当条目被移除的时候回调(详细看代码注释):
public interface ItemTouchMoveListener {
/**
* 当拖拽的时候回调
* 可以在此方法里面实现:拖拽条目并实现刷新效果
* fromPosition 从什么位置拖
* toPosition 到什么位置
* 是否执行了move
*/
boolean onItemMove(int fromPosition, int toPosition);
/**
* 当条目被移除是回调
* position 移除的位置
*/
boolean onItemRemove(int position);
}
接口完成之后开始重写ItemTouchHelper.Callback,来判断用户的动作滑动方向以及选中状态等....
import android.graphics.Canvas;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.support.v7.widget.helper.ItemTouchHelper.Callback;
public class MyItemTouchHelperCallback extends Callback {
private ItemTouchMoveListener moveListener;
public MyItemTouchHelperCallback(ItemTouchMoveListener moveListener) {
this.moveListener = moveListener;
}
//Callback回调监听时先调用的,用来判断当前是什么动作,比如判断方向(意思就是我要监听哪个方向的拖动)
@Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder holder) {
//需要监听的拖拽方向是哪两个方向
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//我要监听的swipe侧滑方向是哪个方向
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int flags = makeMovementFlags(dragFlags, swipeFlags);
return flags;
}
@Override
public boolean isLongPressDragEnabled() {
// 是否允许长按拖拽效果
return true;
}
//当移动的时候回调的方法--拖拽
@Override
public boolean onMove(RecyclerView recyclerView, ViewHolder srcHolder, ViewHolder targetHolder) {
if (srcHolder.getItemViewType() != targetHolder.getItemViewType()) {
return false;
}
// 在拖拽的过程当中不断地调用adapter.notifyItemMoved(from,to);
boolean result = moveListener.onItemMove(srcHolder.getAdapterPosition(), targetHolder.getAdapterPosition());
return result;
}
//侧滑的时候回调的
@Override
public void onSwiped(ViewHolder holder, int arg1) {
// 监听侧滑,1.删除数据;2.调用adapter.notifyItemRemove(position)
moveListener.onItemRemove(holder.getAdapterPosition());
}
@Override
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
//判断选中状态
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.colorAccent));
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
// 恢复
viewHolder.itemView.setBackgroundColor(Color.WHITE);
super.clearView(recyclerView, viewHolder);
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
ViewHolder viewHolder, float dX, float dY, int actionState,
boolean isCurrentlyActive) {
//dX:水平方向移动的增量(负:往左;正:往右)范围:0~View.getWidth 0~1
float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
//透明度动画
viewHolder.itemView.setAlpha(alpha);//1~0
viewHolder.itemView.setScaleX(alpha);//1~0
viewHolder.itemView.setScaleY(alpha);//1~0
}
//删掉一个条目之后,恢复原状
if (alpha == 0) {
viewHolder.itemView.setAlpha(1);//1~0
viewHolder.itemView.setScaleX(1);//1~0
viewHolder.itemView.setScaleY(1);//1~0
}
//此super方法会自动处理setTranslation
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
接下来还需要个接口该接口主要是回调拖拽效果的
import android.support.v7.widget.RecyclerView.ViewHolder;
public interface StartDragListener {
/**
* 该接口用于需要主动回调拖拽效果的
* @param viewHolder
*/
void onStartDrag(ViewHolder viewHolder);}
然后在mainactivity中实现StartDragListener接口,传递给adapter,同时在实现的接口里设置itemTouchHelper.startDrag(viewHolder);
mainactivy完整代码:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements StartDragListener {
private RecyclerView mRecyclerView;
private ArrayList<String> mList;
private MyAdapter mAdapter;
private ItemTouchHelper itemTouchHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.rv);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
mAdapter = new MyAdapter(getData(), this);
mRecyclerView.setAdapter(mAdapter);
//条目触摸帮助类
ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(mAdapter);
itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
}
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
public List<String> getData() {
mList = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
mList.add("item" + i);
}
return mList;
}
}
然后在Adapter中实现数据的交换刷新和移除。
MyAdapter完整代码:
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Collections;
import java.util.List;
public class MyAdapter extends Adapter<MyAdapter.MyViewHolder> implements ItemTouchMoveListener {
private List<String> mList;
private StartDragListener mDragListener;
public MyAdapter(List<String> list, StartDragListener dragListener) {
this.mList = list;
this.mDragListener = dragListener;
}
class MyViewHolder extends ViewHolder {
private ImageView iv;
private TextView tv;
public MyViewHolder(View itemView) {
super(itemView);
iv = (ImageView) itemView.findViewById(R.id.iv);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}
@Override
public int getItemCount() {
return mList.size();
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int location) {
holder.tv.setText(mList.get(location));
holder.iv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//传递触摸情况给谁?
mDragListener.onStartDrag(holder);
}
return false;
}
});
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem, parent, false);
return new MyViewHolder(view);
}
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
// 1.数据交换;2.刷新
Collections.swap(mList, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return true;
}
@Override
public boolean onItemRemove(int position) {
mList.remove(position);
notifyItemRemoved(position);
return true;
}
}
两个简单布局一并贴出:
mainActivity布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.fly.rv03.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
item布局:
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="text" />
</LinearLayout>
</LinearLayout>
再次体验下效果:
长按移动:
------------------------------华丽的分割线-------------------------------------------------------------------------------
RecyclerView先暂时告一段落,下节课我们学习另外一个知识点,敬请期待。。。