First of all, I saw this question: Adding a colored background with text/icon under swiped row when using Android's RecyclerView
However, even though the title s
Using the ItemTouchUiUtil interface provides a robust solution to this. It allows you to have a foreground and background view in your ViewHolder and delegate all the swipe handling to the foreground view. Here is an example that I use for swipe right to remove.
In your ItemTouchHelper.Callback :
public class ClipItemTouchHelper extends ItemTouchHelper.SimpleCallback {
...
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder != null){
final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;
getDefaultUIUtil().onSelected(foregroundView);
}
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;
drawBackground(viewHolder, dX, actionState);
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
@Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
int actionState, boolean isCurrentlyActive) {
final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;
drawBackground(viewHolder, dX, actionState);
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
actionState, isCurrentlyActive);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
final View backgroundView = ((ClipViewHolder) viewHolder).clipBackground;
final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;
// TODO: should animate out instead. how?
backgroundView.setRight(0);
getDefaultUIUtil().clearView(foregroundView);
}
private static void drawBackground(RecyclerView.ViewHolder viewHolder, float dX, int actionState) {
final View backgroundView = ((ClipViewHolder) viewHolder).clipBackground;
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
//noinspection NumericCastThatLosesPrecision
backgroundView.setRight((int) Math.max(dX, 0));
}
}
}
And in your layout file, define the foreground and background views:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/clipRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View style="@style/Divider"/>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/row_selector"
>
<RelativeLayout
android:id="@+id/clipBackground"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@color/swipe_bg"
tools:layout_width="match_parent">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:focusable="false"
android:src="@drawable/ic_delete_24dp"
tools:ignore="ContentDescription"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/clipForeground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/clip_vertical_margin"
android:paddingLeft="@dimen/clip_horizontal_margin"
android:paddingRight="@dimen/clip_horizontal_margin"
android:paddingTop="@dimen/clip_vertical_margin" >
<CheckBox
android:id="@+id/favCheckBox"
android:layout_width="@dimen/view_image_size"
android:layout_height="@dimen/view_image_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="@android:color/transparent"
android:button="@drawable/ic_star_outline_24dp"
android:clickable="true"
android:contentDescription="@string/content_favorite"
/>
...
</RelativeLayout>
</FrameLayout>
</LinearLayout>
I managed to get this to work with the color and an image by extending the answer provided by Sanvywell at : Adding a colored background with text/icon under swiped row when using Android's RecyclerView
I won't recreate the full post (you can follow the link). In brief, I did not create a full view to render during the swipe, but only added a bitmap to the canvas, appropriately positioned to the RecyclerView item.
For people still finding this default, this is the simplest way.
A simple utility class to add a background, an icon and a label to a RecyclerView item while swiping it left or right.
insert to Gradle
implementation 'it.xabaras.android:recyclerview-swipedecorator:1.2.1'
Override onChildDraw method of ItemTouchHelper class
@Override
public void onChildDraw (Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,float dX, float dY,int actionState, boolean isCurrentlyActive){
new RecyclerViewSwipeDecorator.Builder(MainActivity.this, c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
.addBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.my_background))
.addActionIcon(R.drawable.my_icon)
.create()
.decorate();
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
for more info -> https://github.com/xabaras/RecyclerViewSwipeDecorator
Instead of draw over, I believe you should use viewType
Implements getItemViewType(int position)
in adapter, returning different types, e.g. 0 for normal, 1 for swipped
and change onCreateViewHolder etc to return different layout on different viewType
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..
final 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;
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.