上篇给大家介绍了Android一步步带你在RecyclerView上面实现"拖放"和"滑动删除"功能
效果如下:
拖动手柄
在设计一个支持"拖放"的列表时,通常提供一个在触摸时初始化拖拽的"拖动手柄". 因其可发现性和可用性而被Material GuIDelines所推荐,尤其是列表处于"可编辑模式"时.
首先更新item的布局(item_main.xml):
<FrameLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:ID="@+ID/item" androID:layout_wIDth="match_parent" androID:layout_height="?ListPreferredItemHeight" androID:clickable="true" androID:focusable="true" androID:foreground="?selectableItemBackground"> <TextVIEw androID:ID="@+ID/text" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_gravity="center_vertical" androID:layout_marginleft="16dp" androID:textAppearance="?androID:attr/textAppearanceMedium" /> <ImageVIEw androID:ID="@+ID/handle" androID:layout_wIDth="?ListPreferredItemHeight" androID:layout_height="match_parent" androID:layout_gravity="center_vertical|right" androID:scaleType="center" androID:src="@drawable/ic_reorder_grey_500_24dp" /></FrameLayout>
用作"拖放手柄"的图片可以在Material Design Icon找到,也可以方便地通过Android Material Design Icon Generator Plugin添加.
我们曾经提到过,可以通过代码itemtouchhelper.startDrag(RecyclerVIEw.VIEwHolder)
来开启拖动. 所以我们要做的就是更新VIEwHolder来包含新的手柄视图,并设置一个简单的触摸事件接口,以触发startDrag()方法.
我们需要定义一个接口来传递拖动事件.
public interface OnStartDragListener { /** * Called when a vIEw is requesting a start of a drag. * * @param vIEwHolder The holder of the vIEw to drag. */ voID onStartDrag(RecyclerVIEw.VIEwHolder vIEwHolder);}
然后,在ItemVIEwHolder中实现化手柄视图.
public final ImageVIEw handleVIEw;public ItemVIEwHolder(VIEw itemVIEw) { super(itemVIEw); // ... handleVIEw = (ImageVIEw) itemVIEw.findVIEwByID(R.ID.handle);}
并且更新Adapter.
private final OnStartDragListener mDragStartListener;public Recyclerlistadapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener; // ...}@OverrIDepublic voID onBindVIEwHolder(final ItemVIEwHolder holder,int position) { // ... holder.handleVIEw.setontouchListener(new OntouchListener() { @OverrIDe public boolean ontouch(VIEw v,MotionEvent event) { if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { mDragStartListener.onStartDrag(holder); } return false; } });}
完整的Adapter应该看起来像这个.
剩下的是把OnStartDragListener添加到Fragment.
public class RecyclerListFragment extends Fragment implements OnStartDragListener { // ... @OverrIDe public voID onVIEwCreated(VIEw vIEw,Bundle icicle) { super.onVIEwCreated(vIEw,icicle); Recyclerlistadapter a = new Recyclerlistadapter(this); // ... } @OverrIDe public voID onStartDrag(RecyclerVIEw.VIEwHolder vIEwHolder) { mitemtouchhelper.startDrag(vIEwHolder); }}
但你运行之后,可以看到这样的效果:
标示选中视图
在上一篇的基础示例中,被拖拽的item事实上是被选中的,但是没有可视化的标示. 由于显著的理由,这是不受欢迎的,但也很容易修复. 事实上,在itemtouchhelper的帮助下,只要你的VIEwHolder的itemVIEw设置了background集合(selector),就会得到相应的效果. 在Lollipop及之后的版本,item vIEw的elevation在拖拽和滑动期间会增加. 而在之前的版本中,滑动时会有fade效果. 看起来就像:
效果看起来不错,但你可能想要更多的控制. 一种方法是,无论任何时候VIEwHolder被选中或者清空,让item自己处理这种改变. 由此,itemtouchhelper.Callback提供了两种回调.
onSelectedChanged(RecyclerVIEw.VIEwHolder,int). 每一次VIEwHolder的状态,变成drag(ACTION_STATE_DRAG)或者swipe(ACTION_STATE_SWIPE)时,该方法就会被调用. 这时候是将VIEwHolder的状态变成active的完美时刻.
clearVIEw(RecyclerVIEw,RecyclerVIEw.VIEwHolder). 在被拖拽的VIEwHolder放下时,或者是滑动 *** 作取消或者完成时(ACTION_STATE_IDLE),这里会是将ItemVIEw状态设置为IDle的最好的地方.
那么,我们就把两者绑定在一起实现.
首先,创建一个接口,让目标VIEwHolder实现:
/** * NotifIEs a VIEw Holder of relevant callbacks from * {@link itemtouchhelper.Callback}. */public interface itemtouchhelperVIEwHolder { /** * Called when the {@link itemtouchhelper} first registers an * item as being moved or swiped. * Implementations should update the item vIEw to indicate * it's active state. */ voID onItemSelected(); /** * Called when the {@link itemtouchhelper} has completed the * move or swipe,and the active item state should be cleared. */ voID onItemClear();}
接着,触发相应的回调方法:
@OverrIDepublic voID onSelectedChanged(RecyclerVIEw.VIEwHolder vIEwHolder,int actionState) { // We only want the active item if (actionState != itemtouchhelper.ACTION_STATE_IDLE) { if (vIEwHolder instanceof itemtouchhelperVIEwHolder) { itemtouchhelperVIEwHolder itemVIEwHolder = (itemtouchhelperVIEwHolder) vIEwHolder; itemVIEwHolder.onItemSelected(); } } super.onSelectedChanged(vIEwHolder,actionState);}@OverrIDepublic voID clearVIEw(RecyclerVIEw recyclerVIEw,RecyclerVIEw.VIEwHolder vIEwHolder) { super.clearVIEw(recyclerVIEw,vIEwHolder); if (vIEwHolder instanceof itemtouchhelperVIEwHolder) { itemtouchhelperVIEwHolder itemVIEwHolder = (itemtouchhelperVIEwHolder) vIEwHolder; itemVIEwHolder.onItemClear(); }}
现在,剩下的是让ItemVIEwHolder实现itemtouchhelperVIEwHolder:
public class ItemVIEwHolder extends RecyclerVIEw.VIEwHolder implements itemtouchhelperVIEwHolder { // ... @OverrIDe public voID onItemSelected() { itemVIEw.setBackgroundcolor(color.LTGRAY); } @OverrIDe public voID onItemClear() { itemVIEw.setBackgroundcolor(0); }}
考虑到这仅仅是一个示例,我们仅仅是在item处于active状态时设置了灰色背景,当item被清空时,把灰色背景删除了. 如果你的Adapter和itemtouchhelper紧密结对的话,轻易地放弃这个设置也行,转而可以直接在itemtouchhelper.Callback转变item的状态.
GrID布局
如果你想在本项目中转而使用GrIDLayoutManager,你会发现并没有正常地起作用. 原因以及修复原因都很简单: 必须告诉itemtouchhelper我们想要支持左右拖拽. 在SimpletouchHelperCallback中,我们已经声明:
@OverrIDepublic int getMovementFlags(RecyclerVIEw recyclerVIEw,RecyclerVIEw.VIEwHolder vIEwHolder) { int dragFlags = itemtouchhelper.UP | itemtouchhelper.DOWN; int swipeFlags = itemtouchhelper.START | itemtouchhelper.END; return makeMovementFlags(dragFlags,swipeFlags);}
支持GrID布局所要求的唯一改变是dragFlags中添加左右方向:
int dragFlags = itemtouchhelper.UP | itemtouchhelper.DOWN | itemtouchhelper.left | itemtouchhelper.RIGHT;
但是,对于grID而言,"滑动删除"并不是一个天然的功能模式,所以你也许会写一些如下的代码:
@OverrIDepublic int getMovementFlags(RecyclerVIEw recyclerVIEw,RecyclerVIEw.VIEwHolder vIEwHolder) { int dragFlags = itemtouchhelper.UP | itemtouchhelper.DOWN | itemtouchhelper.left | itemtouchhelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags,swipeFlags);}
GrID上面的上下左右"拖放"效果看起来如下:
自定义滑动动画
对我们而言,在vIEwHolder拖拽和滑动的时候,itemtouchhelper.Callback为我们提供了一个十分方便的方式来完全控制VIEwHolder的动画. 因为itemtouchhelper是一个Itemdecoration,我们可以用类似的方式,详细地了解视图的绘制(hook into the VIEw drawing).
下面是一个简单的例子,来覆盖默认的滑动动画,来展示一个线性的fade效果.
@OverrIDepublic voID onChildDraw(Canvas c,RecyclerVIEw recyclerVIEw,VIEwHolder vIEwHolder,float dX,float dY,int actionState,boolean isCurrentlyActive) { if (actionState == itemtouchhelper.ACTION_STATE_SWIPE) { float wIDth = (float) vIEwHolder.itemVIEw.getWIDth(); float Alpha = 1.0f - Math.abs(dX) / wIDth; vIEwHolder.itemVIEw.setAlpha(Alpha); vIEwHolder.itemVIEw.setTranslationX(dX); } else { super.onChildDraw(c,recyclerVIEw,vIEwHolder,dX,dY,actionState,isCurrentlyActive); }}
参数dX和dY代表选中视图的当前位置,
-1.0f表示完完全全的从itemtouchhelper.END到itemtouchhelper.START的滑动. 1.0f表示完完全全的从itemtouchhelper.START到itemtouchhelper.END的滑动.对于任何没有处理的actionState你都可以调用super的方法,从而使用默认的动画.
总结
我们仅仅了解了自定义itemtouchhelper所能做的事情中有趣的部分,我希望能够在一篇文章中包含更多内容,但是考虑到文章长度,还是分开比较好.
以上所述是小编给大家介绍的AndroID开发在RecyclerVIEw上面实现"拖放"和"滑动删除功能(二),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!
总结以上是内存溢出为你收集整理的Android开发在RecyclerView上面实现"拖放"和"滑动删除"-2全部内容,希望文章能够帮你解决Android开发在RecyclerView上面实现"拖放"和"滑动删除"-2所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)