Drag and Swipe in RecyclerView. Part 2: Drag and Drop Controllers, Grid, and Custom Animations

 3r? 3591. 3r3-31. 3r33576. [img]https://drive.google.com/uc?id=1Xf3q0l4XRgLhY8QLsNXJFHXO73iBBvBz[/img] 3r???. 3r? 3574.  3r? 3591. 3r33576. In 3r? 3577. the first part 3r3578. we reviewed r3r310. ItemTouchHelper
and implementation 3r312. ItemTouchHelper.Callback
which adds basic functions
drag & drop
and 3r33531. swipe-to-dismiss
in 3r33545. RecyclerView . In this article, we will continue what was done in the previous one, adding support for the arrangement of elements in a grid, drag-and-drop controllers, selection of a list item and custom swipe animations (3r-3285? eng. 3r-?386. Swipe). 3r???. plug-in icon generator in Android Studio. 3r???. 3r? 3574.  3r? 3591. 3r33576. As briefly mentioned in the last article, you can use 3r33545. ItemTouchHelper.startDrag (ViewHolder) to programmatically start dragging. So, all we have to do is update 3r33545. ViewHolder by adding a drag controller, and set up a simple touch handler that will call 3r3353545. startDrag () . 3r???. 3r? 3574.  3r? 3591. 3r33576. We need an interface to send the event through the chain: 3r33535. 3r? 3574.  3r? 3591.
3r33490. public interface OnStartDragListener {
3r? 3591. /
* Called when a view is requesting a start of a drag. 3r? 3591. *
* @param viewHolder 3r? 3591. * /
void onStartDrag (RecyclerView.ViewHolder viewHolder); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. Then define 3r33545. ImageView 3r33546. for the drag and drop controller in 3r3353545. ItemViewHolder :
3r? 3574.  3r? 3591.
3r33490. public final ImageView handleView; 3r? 3591. public ItemViewHolder (View itemView) {
super (itemView); 3r? 3591. //3r3591. handleView = (ImageView) itemView.findViewById (R.id.handle); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. and update RecyclerListAdapter : 3r? 3574.  3r? 3591.
  3r33490. private final OnStartDragListener mDragStartListener; 3r? 3591. 3r? 3591. public RecyclerListAdapter (OnStartDragListener dragStartListener) {
mDragStartListener = dragStartListener; 3r? 3591. //3r3591.}
@Override
public void onBindViewHolder (final ItemViewHolder holder,
int position) {
//3r3591. holder.handleView. .onStartDrag (holder); 3r3–3591.} 3r3–3591. return false; 3r3–3591.} 3r33591.}); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. 3r33545. RecyclerListAdapter should now look about so . 3r???. 3r? 3574.  3r? 3591. 3r33576. All that's left to do is add 3r33545. OnStartDragListener in the fragment: 3r37979. 3r? 3574.  3r? 3591.
  3r33490. public class RecyclerListFragment extends Fragment implements
OnStartDragListener {
3r? 3591. //3r3591. @Override
public void onViewCreated (View view, Bundle icicle) {
super.onViewCreated (view, icicle); 3r? 3591. 3r? 3591. RecyclerListAdapter a = new RecyclerListAdapter (this); 3r? 3591. //3r3591.}
@Override
public void onStartDrag (RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag (viewHolder); 3r? 3591.}
} 3r33535.
3r? 3574.  3r? 3591. 3r33576. 3r33545. RecyclerListFragment should now look like as follows r3r3578. . Now, when you start the application, you can start dragging by touching the controller. 3r???. 3r? 3574.  3r? 3591. 3r33576. [img]https://drive.google.com/uc?id=18FVh7B16VIkUZPFsbftkXho_5IVRiZUS[/img] 3r???. 3r? 3574.  3r? 3591.

Selecting a list item

3r? 3574.  3r? 3591. 3r33576. Now in our example, there is no visual indication of an item that is being dragged. Obviously this should not be so, but it is easy to fix. With the help of 3r34545. ItemTouchHelper You can use standard element highlighting effects. On Lollipop and later versions of Android, the backlight “blurs” over the element as it interacts with it; in earlier versions, the element simply changes its color to darkened. 3r???. 3r? 3574.  3r? 3591. 3r33576. To implement this in our example, simply add a background (property 3r33545. Background 3r33535.) To the root 3r3353545. FrameLayout element
item_main.xml or install it in constructor RecyclerListAdapter.ItemViewHolder . It will look something like this: 3r? 3574.  3r? 3591. 3r33576. [img]https://drive.google.com/uc?id=1fLF7VIhM7ZD86Tm3kYJmnM_rt5SFadzf[/img] 3r???. 3r? 3574.  3r? 3591. 3r33576. It looks cool, but you might want to control even more. One way to do this is to allow 3r3353545. ViewHolder handle element state changes. For this 3r34545. ItemTouchHelper.Callback provides two more methods: 3r? 3574.  3r? 3591. 3r? 3519.  3r? 3591. 3r? 3530. 3r33545. onselectedChanged (ViewHolder, int) called whenever the state of an element changes to 3r33531. drag ( ACTION_STATE_DRAG ) Or 3r3353531. swipe 3r33235. ( ACTION_STATE_SWIPE 3r3-3578.). This is the perfect place to change the state of 3r3353545. view -component on active. . 3r33537.  3r? 3591. 3r? 3530. 3r33545. clearView (RecyclerView, ViewHolder) Called when dragging is complete 3r3353545. view -component, as well as at the completion of brushing (3r3-33283. ACTION_STATE_IDLE ). is usually restored here. original 3r33286. condition of your 3r34545. view -component. 3r33537.  3r? 3591. 3r? 3539. 3r? 3574.  3r? 3591. 3r33576. And now let's just put it all together. 3r???. 3r? 3574.  3r? 3591. 3r33576. First create an interface that will implement 3r33545. ViewHolders : 3r? 3574.  3r? 3591.
  3r33490. /
* Callbacks from
* {@link ItemTouchHelper.Callback}. 3r? 3591. * /
public interface ItemTouchHelperViewHolder {
3r? 3591. /
* Called when the {@link ItemTouchHelper} first registers an
* item as being moved or swiped. 3r? 3591. *
Implementations should not be taken. * it's active state. 3r? 3591. * /
void onItemSelected (); 3r? 3591. 3r? 3591. /
* Called when the {@link ItemTouchHelper} has completed the
* move or swipe, it should be cleared. 3r? 3591. * /
void onItemClear (); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. Then in 3r34545. SimpleItemTouchHelperCallback implement the appropriate methods: 3r? 3574.  3r? 3591.
  3r33490. @Override
public 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; 3r? 3591. itemViewHolder.onItemSelected (); 3r? 3591.}
}
3r? 3591. super.onselectedChanged (viewHolder, actionState); 3r? 3591.}
@Override
public void clearView (RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
super.clearView (recyclerView, viewHolder); 3r? 3591. 3r? 3591. if (viewHolder instanceof ItemTouchHelperViewHolder) {
ItemTouchHelperViewHolder itemViewHolder =
(ItemTouchHelperViewHolder) viewHolder; 3r? 3591. itemViewHolder.onItemClear (); 3r? 3591.}
} 3r33535.
3r? 3574.  3r? 3591. 3r33576. Now it remains only to RecyclerListAdapter.ItemViewHolder implemented 3r34545. ItemTouchHelperViewHolder : 3r? 3574.  3r? 3591.
  3r33490. public class ItemViewHolder extends RecyclerView.ViewHolder
implements ItemTouchHelperViewHolder {
3r? 3591. //3r3591. @Override
public void onItemSelected () {
itemView.setBackgroundColor (Color.LTGRAY); 3r? 3591.}
3r? 3591. @Override
public void onItemClear () {3r33551. itemView.setBackgroundColor (0); 3r? 3591.}
} 3r33535.
3r? 3574.  3r? 3591. 3r33576. In this example, we simply add a gray background while the item is active, and then delete it. If your 3r33545. ItemTouchHelper and the adapter is tightly coupled, you can easily drop this setting and switch the state of 3r3353545. view -component straight into r3r3545. ItemTouchHelper.Callback . 3r???. 3r? 3574.  3r? 3591. 3r3402. Grid 3r36363. 3r? 3574.  3r? 3591. 3r33576. If now you try to use GridLayoutManager , you will see that it is not working properly. Cause and SolutionThe points are simple: we have to tell our 3r3353545. ItemTouchHelper that we want to support dragging left and right. Earlier in 3r34545. SimpleItemTouchHelperCallback we have already indicated: 3r? 3574.  3r? 3591.
  3r33490. @Override
public int getMovementFlags (RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; 3r? 3591. int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; 3r? 3591. return makeMovementFlags (dragFlags, swipeFlags); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. The only change needed to support the grids is to add the appropriate flags: 3r-3579. 3r? 3574.  3r? 3591.
  3r33490. int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | 3r? 3591. ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 3r33546.  
3r? 3574.  3r? 3591. 3r33576. However, r3r3531. swipe-to-dismiss not very natural behavior for elements in the form of a grid, therefore 3r33545. swipeFlags the most reasonable to reset: 3r? 3574.  3r? 3591.
  3r33490. @Override
public int getMovementFlags (RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | 3r? 3591. ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 3r? 3591. int swipeFlags = 0; 3r? 3591. return makeMovementFlags (dragFlags, swipeFlags); 3r? 3591.} 3r33535.
3r? 3574.  3r? 3591. 3r33576. To see the working example 3r33545. GridLayoutManager See 3r36363. RecyclerGridFragment . Here's what it looks like at startup: 3r? 3574.  3r? 3591. 3r33576. 3r33469. 3r???. 3r? 3574.  3r? 3591. 3r33473. Custom swipe animations 3r? 3574.  3r? 3591. 3r33576. 3r33545. ItemTouchHelper.Callback provides a really convenient way to fully control the animation while dragging or swiping. Since 3r33545. ItemTouchHelper - this is RecyclerView.ItemDecoration , we can intervene in the drawing process 3r33545. view -component in a similar way. In the next part, we will examine this question in more detail, but for now let's look at a simple example of overriding the default swipe animation to show linear disappearance. 3r???. 3r? 3574.  3r? 3591.
  3r33490. @Override
public void onChildDraw (Canvas c, RecyclerView recyclerView,
ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {3r33551. 3r? 3591. if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
float width = (float) viewHolder.itemView.getWidth (); 3r? 3591. float alpha = 1.0f - Math.abs (dX) /width; 3r? 3591. viewHolder.itemView.setAlpha (alpha); 3r? 3591. viewHolder.itemView.setTranslationX (dX); 3r? 3591.} else {
super.onChildDraw (c, recyclerView, viewHolder, dX, dY,
actionState, isCurrentlyActive); 3r? 3591.}
} 3r33535.
3r? 3574.  3r? 3591. 3r33576. Parameters 3r3-3545. dX 3r33546. and 3r33545. dY 3r33546. - this is the current shift relative to the selected 3r33545. view -component, where: 3r? 3574.  3r? 3591. 3r? 3519.  3r? 3591. 3r? 3530. 3r? 3531. -1.0f - this is a full swipe from right to left (from 3r33545. ItemTouchHelper.END 3r33546. To 3r34545. ItemTouchHelper. START ) 3r33537.  3r? 3591. 3r? 3530. 3r? 3531. 1.0f 3r33232. - this is a complete swipe from left to right (from 3r33545. ItemTouchHelper. START To 3r33545. ItemTouchHelper. ENnd 3r33546.) 3r33537  3r? 3591. 3r? 3539. 3r? 3574.  3r? 3591. 3r33576. It is important to call 3r34545. super 3r33546. for any 3r34545. actionState , which you do not handle, in order to start the default animation. 3r???. 3r? 3574.  3r? 3591. 3r33576. In the next part, we will look at an example in which we will control the drawing of an element at the moment of dragging. 3r???. 3r? 3574.  3r? 3591. 3r33554. Conclusion 3r36363. 3r? 3574.  3r? 3591. 3r33576. In fact, setting up an ItemTouchHelper is quite fun. In order not to increase the volume of this article, I divided it into several. 3r???. 3r? 3574.  3r? 3591. 3r? 3562. The source code is 3r36363. 3r? 3574.  3r? 3591. 3r33576. See the GitHub repositories of 3r33567 for the full code for this series of articles. Android-ItemTouchHelper-Demo
. This article covers commits from 3r3-3569. ef8f149 r3r3578. to 3r???. d164fba
. 3r???. 3r? 3574.  3r? 3591. 3r33576. 3r? 3577. ← Drag and Swipe in RecyclerView. Part 1: ItemTouchHelper
3r???. 3r33587. 3r? 3591. 3r? 3591. 3r? 3591. 3r33584. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//mediator.mail.ru/script/2820404/"""_mediator") () (); 3r33585. 3r? 3591. 3r33587. 3r? 3591. 3r? 3591. 3r? 3591. 3r? 3591.
+ 0 -

Add comment