标签:adapter 手势 public 重写 解析 pad lin log tle
ItemTouchHelper
在RecyclerView
的整个体系中,负责监听Item
的手势操作,我们通过给它设置一个继承于ItemTouchHelper.Callback
的子类,在其中处理Item
的UI
变化,就可以完成侧滑删除、拖动排序等操作,下面,我们分以下几部介绍:
API
解析API
分析对于Item
的手势操作分为两种:侧滑和拖动,如果需要支持这两种,那么需要给ItemTouchHelper
传入一个ItemTouchHelper.Callback
的子类,并把ItemTouchHelper
和RecyclerView
关联起来,下面,我们先来介绍一下ItemTouchHelper.Callback
个回调方法的含义:
public boolean isLongPressDragEnabled()
true
,如果返回false
,那么可以通过startDrag(ViewHolder)
方法来触发某个特定Item
的拖动的机制。public boolean isItemViewSwipeEnabled()
Item
进行侧滑。public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
ViewHolder
可以移动的方向,可选的值有UP/DOWN/LEFT/RIGHT/START/END
。对于纵向排列的线性布局而言,如果要支持上下拖动排序,那么就要标志位中就要包含UP&DOWN
,而如果需要支持左滑删除,那么标志位中就要包含LEFT
。public abstract boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target)
Item
被从旧位置拖动到了新位置后回调,如果返回true
,那么ItemTouchHelper
就认为viewHolder
已经被移动到了target
在Adapter
中的位置。public abstract void onSwiped(ViewHolder viewHolder, int direction)
Item
被滑动到消失时回调,direction
表示滑动的方向。public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
Item
的状态发生改变时,回调该方法,actionState
的取值有ACTION_STATE_IDLE/ACTION_STATE_SWIPE/ACTION_STATE_DRAG
。public void clearView(RecyclerView recyclerView, ViewHolder viewHolder)
Item
的操作并且Item
的动画结束,此时我们应该恢复它的状态,以保证它被重新使用的时候能正确地展现。public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
Canvas
:绘制RecyclerView
的Canvas
dx, dy
:偏移。actionState
:拖拽还是侧滑,对应ACTION_STATE_DRAG
和ACTION_STATE_SWIPE
。isCurrentlyActive
为true
表示这个Item
正在被用户所控制,false
则表示它仅仅是在回到原本状态的动画过程当中。public void onChildDrawOver(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
和上面类似,只不过它是绘制在Item
之上。
如果我们希望使用系统默认的效果,那么只需要做以下几步:
继承于ItemTouchHelper.Callback
编写自己的回调类,并在拖动和侧滑操作完成之后更新数据:
public class SimpleItemTouchHelper extends ItemTouchHelper.Callback {
private ItemTouchAdapter mAdapter;
public SimpleItemTouchHelper(ItemTouchAdapter adapter) {
mAdapter = adapter;
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Log.d("SimpleItemTouchHelper", "onSwiped, onMove, source=" + viewHolder.getAdapterPosition() + ",target=" + target.getAdapterPosition());
mAdapter.onItemDragged(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
Log.d("SimpleItemTouchHelper", "onSwiped, direction=" + direction);
mAdapter.onItemSwiped(viewHolder.getAdapterPosition());
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
}
}
编写数据操作的代码:
public class NormalAdapter extends RecyclerView.Adapter<NormalAdapter.NormalViewHolder> implements ItemTouchAdapter {
//......
@Override
public void onItemDragged(int from, int to) {
Collections.swap(mTitles, from, to);
notifyItemMoved(from, to);
}
@Override
public void onItemSwiped(int position) {
mTitles.remove(position);
notifyItemRemoved(position);
}
}
ItemTouchHelper.Callback
和RecyclerView
关联起来,看注释中的1,2,3
步:
private void init() {
List<String> titles = new ArrayList<>();
for (int i = 0; i < 20; i++) {
titles.add(String.valueOf(i));
}
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_content);
recyclerView.setLayoutManager(layoutManager);
NormalAdapter adapter = new NormalAdapter(titles);
//1.自定义的ItemTouchHeloer.Callback
SimpleItemTouchHelper simpleItemTouchHelper = new
SimpleItemTouchHelper(adapter);
//2.利用这个Callback构造ItemTouchHelper
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchHelper);
//3.把ItemTouchHelper和RecyclerView关联起来.
itemTouchHelper.attachToRecyclerView(recyclerView);
recyclerView.setAdapter(adapter);
}
下面就是最终的效果:当我们需要自定侧滑删除动画时,那么需要重写onChildDraw
或者onChildDrawOver
方法,在其中监听滑动距离的变化,并根据它来实时改变viewHolder
中的UI
,首先看效果:
首先,我们需要重写Item
的布局,它包含两层,顶层是普通状态的标题文案,而底层则是蓝色底的删除提示:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="66dp">
<!-- 删除提示 -->
<LinearLayout
android:id="@+id/ll_delete"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="end"
android:background="@android:color/holo_blue_dark"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageView
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="delete"
android:textColor="@android:color/white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 普通文案 -->
<TextView
android:id="@+id/tv_title"
android:gravity="center"
android:background="@android:color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
接着,我们需要重写ItemTouchHelper.Callback
:
public class AdvancedItemTouchHelper extends ItemTouchHelper.Callback {
private ItemTouchAdapter mAdapter;
public AdvancedItemTouchHelper(ItemTouchAdapter itemTouchAdapter) {
mAdapter = itemTouchAdapter;
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, ItemTouchHelper.LEFT);
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemSwiped(viewHolder.getAdapterPosition());
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
((NormalAdapter.NormalViewHolder) viewHolder).mTv.setTranslationX(0);
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
NormalAdapter.NormalViewHolder mViewHolder = (NormalAdapter.NormalViewHolder) viewHolder;
int deleteWidth = mViewHolder.mDeleteLayout.getWidth();
float fraction = deleteWidth / (float) mViewHolder.itemView.getWidth();
mViewHolder.mTv.setTranslationX(dX * fraction);
}
}
这里面有几点需要注意:
Item
支持左滑删除,我们需要在getMovementFlags
中返回ItemTouchHelper.LEFT
标志位。onChildDraw
当中,通过传入的dX
动态改变了普通文案的translationX
,使得底层的删除提示能够漏出。Adapter
来删除数据。clearView
中,需要把mTv
重置为初始的状态。最后,我们按照前面的方法,把它和RecyclerView
关联起来:
private void init() {
List<String> titles = new ArrayList<>();
for (int i = 0; i < 20; i++) {
titles.add("Item " + String.valueOf(i));
}
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_content);
recyclerView.setLayoutManager(layoutManager);
NormalAdapter adapter = new NormalAdapter(titles);
AdvancedItemTouchHelper advancedItemTouchHelper = new AdvancedItemTouchHelper(adapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(advancedItemTouchHelper);
itemTouchHelper.attachToRecyclerView(recyclerView);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.setAdapter(adapter);
}
自定义RecyclerView
的手势动画,关键是要理解ItemTouchHelper.Callback
中各回调函数的含义,再通过回调函数中传入的数值来动态改变viewHolder
中保存的itemView
以及其子View
的展现形式,就可以做出各种绚丽的效果。
RecyclerView 知识梳理(5) - ItemTouchHelper
标签:adapter 手势 public 重写 解析 pad lin log tle
原文地址:http://www.cnblogs.com/youseiraws/p/7071161.html