Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView Swipe with a view below it

I have been doing some research and I have yet to find an example or implementation that allows you to put a view (Example Image Below) underneath the RecyclerView when you swipe. Does anyone have any example or an idea of how this would be implemented WITHOUT using a library.

Here is how I am implementing the swipe to dismiss.

ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {      @Override     public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {         return false;     }      @Override     public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {         return super.getSwipeDirs(recyclerView, viewHolder);     }      @Override     public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {         if (viewHolder instanceof ViewDividers) {             Log.e("DIRECTION", direction + "");         }     } }; new ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recycler); 

Here is the example of Google's Inbox: enter image description here

like image 950
Eugene H Avatar asked Aug 26 '15 13:08

Eugene H


2 Answers

My understanding of how this is done is that one would put two views in the xml that would be displayed per line in your recyclerview.

So for example, this would be my adapter:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {     public static class ExampleViewHolder extends RecyclerView.ViewHolder {         public TextView background;         public TextView foreground;          public ExampleViewHolder(View v) {             super(v);             background = (TextView) v.findViewById(R.id.background);             foreground = (TextView) v.findViewById(R.id.foreground);         }          @Override         public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {             if (holder instanceof ExampleViewHolder) {                 ((ExampleViewHolder) holder).background.setBackgroundColor(); // do your manipulation of background and foreground here.             }         }          @Override         public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,                                                           int viewType) {              View v = LayoutInflater.from(parent.getContext())                     .inflate(R.layout.example, parent, false);             return new ExampleViewHolder(v);         }       } } 

Each line in the recyclerview is pulling the xml layout from R.layout.example. Therefore, to create a view underneath, you can just use relativelayout or framelayout to create the views on top of one another:

<RelativeLayout     android:layout_width="match_parent"     android:layout_height="wrap_content">      <TextView         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:id="@+id/background"         />      <TextView         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:id="@+id/foreground"/> </RelativeLayout> 

Then if you do not want to use a library for the swipe, you can copy this class from google and subsequently modified by Bruno Romeu Nunes:

https://github.com/heruoxin/Clip-Stack/blob/master/app/src/main/java/com/catchingnow/tinyclipboardmanager/SwipeableRecyclerViewTouchListener.java

The class will require you to create a swipe listener:

swipeTouchListener =         new SwipeableRecyclerViewTouchListener(mRecyclerView,                 new SwipeableRecyclerViewTouchListener.SwipeListener() {                     @Override                     public boolean canSwipe(int position) {                         if (position == totalPost.size() - 1 && !connected) {                             return false;                         }                         return true;                     }                      @Override                     public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {                         for (int position : reverseSortedPositions) {                             //change some data if you swipe left                         }                         myAdapter.notifyDataSetChanged();                     }                      @Override                     public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {                         for (int position : reverseSortedPositions) {                             //change some data if you swipe right                         }                         myAdapter.notifyDataSetChanged();                     }                 }); 

Then simply link it with your recyclerview:

    mRecyclerView.addOnItemTouchListener(swipeTouchListener); 
like image 112
Simon Avatar answered Sep 28 '22 12:09

Simon


I was investigating the same issue.
What i ended up doing was, in the layout that contained the recyclerView, I added a simple FrameLayout called 'swipe_bg' of the same height as one of my RecyclerView.ViewHolder items. I set its visibility to "gone", and placed it under the RecyclerView

Then in my activity where i set the ItemTouchHelper, I override the onChildDraw like so..

ItemTouchHelper.SimpleCallback swipeCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT) {      @Override     public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {          View itemView = viewHolder.itemView;          Imageview swipe_bg = itemView.findViewById(R.id.imageview_swipe_background);          swipe_bg.setY(itemView.getTop());          if (isCurrentlyActive) {              swipe_bg.setVisibility(View.VISIBLE);          } else {              swipe_bg.setVisibility(View.GONE);          }          super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);     } }; 

Don't know if that is the best way, but seemed like the simplest way.

like image 38
erik Avatar answered Sep 28 '22 12:09

erik