Android開發之RecyclerView的互動動畫(實現拖拽和刪除)
阿新 • • 發佈:2019-02-10
做RecyclerView做相關的動畫效果的時候,用的最多的是v7包下的ItemTouchHelper類,這個類很強大,如有興趣的童鞋可以自行翻看原始碼,接下來我帶領大家實現RecyclerView相關的互動動畫。大家看下面的效果(拖拽和刪除):
------------------------------------------華麗的分割線---------------------------------------------------------------------
實現原理:通過重寫ItemTouchHelper類的callback回撥方法,然後itemTouchHelper.attachToRecyclerView(mRecyclerView)來實現item的拖拽和刪除。
------------------------------------------華麗的分割線---------------------------------------------------------------------
首先我們需要先定義一個介面
當拖拽的時候回撥和當條目被移除的時候回撥(詳細看程式碼註釋):
介面完成之後開始重寫ItemTouchHelper.Callback,來判斷使用者的動作滑動方向以及選中狀態等....public interface ItemTouchMoveListener { /** * 當拖拽的時候回撥 * 可以在此方法裡面實現:拖拽條目並實現重新整理效果 * fromPosition 從什麼位置拖 * toPosition 到什麼位置 * 是否執行了move */ boolean onItemMove(int fromPosition, int toPosition); /** * 當條目被移除是回撥 * position 移除的位置 */ boolean onItemRemove(int position); }
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先暫時告一段落,下節課我們學習另外一個知識點,敬請期待。。。