Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a colored background with text/icon under swiped row when using Android's RecyclerView

EDIT: The real problem was that my LinearLayout was wrapped in another layout, which caused the incorrect behavior. The accepted answer by Sanvywell has a better, more complete example of how to draw a color under swiped view than the code snippet I provided in the question.

Now that RecyclerView widget has native support for row swiping with the help of ItemTouchHelper class, I'm attempting to use it in an app where rows will behave similarly to Google's Inbox app. That is, swiping to the left side performs one action and swiping to the right does another.

Implementing the actions themselves was easy using ItemTouchHelper.SimpleCallback's onSwiped method. However, I was unable to find a simple way to set color and icon that should appear under the view that's currently being swiped (like in Google's Inbox app).

To do that, I'm trying to override ItemTouchHelper.SimpleCallback's onChildDraw method like this:

@Override public void onChildDraw(Canvas c, RecyclerView recyclerView,                         RecyclerView.ViewHolder viewHolder, float dX, float dY,                         int actionState, boolean isCurrentlyActive) {     RecyclerViewAdapter.ViewHolder vh = (RecyclerViewAdapter.ViewHolder) viewHolder;     LinearLayout ll = vh.linearLayout;      Paint p = new Paint();     if(dX > 0) {         p.setARGB(255, 255, 0, 0);     } else {         p.setARGB(255, 0, 255, 0);     }      c.drawRect(ll.getLeft(), ll.getTop(), ll.getRight(), ll.getBottom(), p);      super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } 

Determining the swipe direction from dX and setting the appropriate color works as intended, but the coordinates I get from the ViewHolder always correspond to the place where the first LinearLayout was inflated.

How do I get the correct coordinates for the LinearLayout that's in the currently swiped row? Is there an easier way (that doesn't require to override onChildDraw) to set the background color and icon?

like image 709
Manvis Avatar asked Jun 13 '15 16:06

Manvis


2 Answers

I was struggling to implement this feature as well, but you steered me in the right direction.

@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {     if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {         // Get RecyclerView item from the ViewHolder         View itemView = viewHolder.itemView;          Paint p = new Paint();         if (dX > 0) {             /* Set your color for positive displacement */              // Draw Rect with varying right side, equal to displacement dX             c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX,                     (float) itemView.getBottom(), p);         } else {             /* Set your color for negative displacement */              // Draw Rect with varying left side, equal to the item's right side plus negative displacement dX             c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(),                     (float) itemView.getRight(), (float) itemView.getBottom(), p);         }          super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);     } } 
like image 54
user5055032 Avatar answered Sep 24 '22 04:09

user5055032


The accepted answer does a great job of coloring the background, but did not address drawing the icon.

This worked for me because it both set the background color and drew the icon, without the icon being stretched during the swipe, or leaving a gap between the previous and next items after the swipe.

public static final float ALPHA_FULL = 1.0f;  public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {     if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {         // Get RecyclerView item from the ViewHolder         View itemView = viewHolder.itemView;          Paint p = new Paint();         Bitmap icon;          if (dX > 0) {             /* Note, ApplicationManager is a helper class I created                 myself to get a context outside an Activity class -                 feel free to use your own method */              icon = BitmapFactory.decodeResource(                     ApplicationManager.getContext().getResources(), R.drawable.myleftdrawable);              /* Set your color for positive displacement */             p.setARGB(255, 255, 0, 0);              // Draw Rect with varying right side, equal to displacement dX             c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX,                     (float) itemView.getBottom(), p);              // Set the image icon for Right swipe             c.drawBitmap(icon,                     (float) itemView.getLeft() + convertDpToPx(16),                     (float) itemView.getTop() + ((float) itemView.getBottom() - (float) itemView.getTop() - icon.getHeight())/2,                     p);         } else {             icon = BitmapFactory.decodeResource(                     ApplicationManager.getContext().getResources(), R.drawable.myrightdrawable);              /* Set your color for negative displacement */             p.setARGB(255, 0, 255, 0);              // Draw Rect with varying left side, equal to the item's right side             // plus negative displacement dX             c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(),                     (float) itemView.getRight(), (float) itemView.getBottom(), p);              //Set the image icon for Left swipe             c.drawBitmap(icon,                     (float) itemView.getRight() - convertDpToPx(16) - icon.getWidth(),                     (float) itemView.getTop() + ((float) itemView.getBottom() - (float) itemView.getTop() - icon.getHeight())/2,                     p);         }          // Fade out the view as it is swiped out of the parent's bounds         final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();         viewHolder.itemView.setAlpha(alpha);         viewHolder.itemView.setTranslationX(dX);      } else {         super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);     } }  private int convertDpToPx(int dp){     return Math.round(dp * (getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT)); } 
like image 42
HappyKatz Avatar answered Sep 22 '22 04:09

HappyKatz