9

I have created RecyclerView which contains CardView in order to show data. I would like to implement iOS style of swiping list elements to show action buttons. My method which should allow me to show icon after swiping left an RecyclerView item:

public void initializeListeners() {
        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 void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                int position = viewHolder.getAdapterPosition();

                if (direction == ItemTouchHelper.LEFT) {
                    Toast.makeText(getView().getContext(),"LEFT",Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

                Bitmap icon;
                if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {

                    View itemView = viewHolder.itemView;
                    float height = (float) itemView.getBottom() - (float) itemView.getTop();
                    float width = height / 3;

                   if (dX < 0) {
                        p.setColor(Color.parseColor("#D32F2F"));
                        RectF background = new RectF((float) itemView.getRight() + dX/4, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom());
                        c.drawRect(background, p);
                        icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_delete_black_24dp);
                        RectF icon_dest = new RectF((float) itemView.getRight() - 2 * width, (float) itemView.getTop() + width, (float) itemView.getRight() - width, (float) itemView.getBottom() - width);
                        c.drawBitmap(icon, null, icon_dest, p);

                    }
                }
                super.onChildDraw(c, recyclerView, viewHolder, dX/4, dY, actionState, isCurrentlyActive);
            }
        };
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
        itemTouchHelper.attachToRecyclerView(binding.myPlans);

    }

effect of this is: enter image description here

I would like to make this icon clickable in order to send HTTP request using id of object of clicked possition in RecyclerView (after alertview confirmation)

is it possible? I was trying to replace Bitmap for ImageButton with no success

Mithrand1r
  • 2,313
  • 9
  • 37
  • 76
  • a much simpler approach would to be to manipulate the UI, add an imageview on top and move right or left to your liking. – Khaledonia Mar 07 '17 at 12:11

3 Answers3

7

If you consider Swipeable items in lists, the logic is a bit different for Android and iOS. In Android you don't need to confirm deletion with a click. The fact that user swiped the item is enough of a confirmation.

That's why ItemTouchHelper won't give you a way to attach an OnClickListener.

You have two choices:

  1. You can write your own custom swipe management system (painful).
  2. Agree on Android way of doing that and ask user for confirmation after the swipe.
Bartek Lipinski
  • 30,698
  • 10
  • 94
  • 132
6

I wrote a blog post describing the steps needed for implementing this kind of feature.

  • Add the following class to your project: SwipeRevealLayout.java
  • Adjust your layout code for your RecyclerView ViewHolder and add the SwipeRevealLayout component as the container for both the top and bottom layer of your RecyclerView Item. For an example of how to set it up: list_item_main.xml
  • Ensure the bottom layer is the first layout component within the SwipeRevealLayout container.
  • Make sure to use ‘wrap_content’ or a predefined width for your bottom layer. I tested out using ‘match_parent’ and the top layer did a good magic trick and disappeared.
  • If you are adding a clickable function on the bottom layer, ensure the top layer has android:clickable=”true” otherwise clicks for the bottom layer components will still trigger when you click on the top layer.
  • Optional: You can define what edge you want to drag from. By default, it will drag from the left, in the example project I defined it to drag from the right. Specify it with app:dragFromEdge=”{edge to drag from}" when specifying the attributes for the SwipeRevealLayout component.

If you're interested in viewing the full blog post, check it out here: https://android.jlelse.eu/android-recyclerview-swipeable-items-46a3c763498d

Mark O'Sullivan
  • 10,138
  • 6
  • 39
  • 60
  • Please fix this critical issue in your class. Thanks in advance. https://github.com/MarkOSullivan94/SwipeRevealLayoutExample/issues/1 – valerybodak Mar 26 '20 at 10:59
0

The background drawn is a Canvas, Canvas don't allow to implements clicks.

I have found a way to simulate the click on your trash view within the onInterceptTouchEvent of RecyclerView.OnItemTouchListener.

First, in your onBindViewHolder you have to set the tag of your view as it viewHolder : viewHolder.itemView.setTag(viewHolder).

Then :

@Override
public void onInterceptTouchEvent (RecyclerView rv, MotionEvent e) {
    View viewSwipedRight = rv.findChildViewUnder(e.getX() - rv.getWidth(), e.getY());
    if (viewSwipedRight != null && e.getAction() == MotionEvent.ACTION_DOWN) {
        ViewHolder viewHolder = (ViewHolder) viewSwipedRight.getTag();
        if (e.getX() >= viewHolder.trashIcon.getX()) {
            // Your icon is clicked !
        }
    }
}

Explanation :

When swiped left, your view is still here, but not on screen because it has moved at the left of the recyclerview, so View viewSwipedRight = rv.findChildViewUnder(e.getX() - rv.getWidth(), e.getY()); will find the view at your Y click at the left of the recyclerView on screen (thanks to e.getX() - rv.getWidth()).

Then you look if the event X matches with your trash icon's X within its own view with e.getX() >= viewHolder.trashIcon.getX() (your trashIcon has to be in your viewHolder).

If both of those conditions match, you have clicked your trash icon.

lolo.io
  • 770
  • 5
  • 22