10

I have a recycler view in which i want to show another layout on swiping item view which is hidden behind the current layout. In short i want to achieve something like below image.

enter image description here

The problem with my code is that the the whole view is swiped, but i want to swipe only to the width of the hidden layout.

Code in Activity

final ItemTouchHelper.Callback simpleItemTouchCallback = new ItemTouchHelper.Callback() {
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                if (viewHolder.getAdapterPosition() < target.getAdapterPosition()) {
                    for (int i = viewHolder.getAdapterPosition(); i < target.getAdapterPosition(); i++) {
                        Collections.swap(myDataset, i, i + 1);
                    }
                } else {
                    for (int i = viewHolder.getAdapterPosition(); i > target.getAdapterPosition(); i--) {
                        Collections.swap(myDataset, i, i - 1);
                    }
                }
                mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
                return true;
            }

            @Override
            public boolean isLongPressDragEnabled() {
                return true;
            }
            @Override
            public boolean isItemViewSwipeEnabled() {
                return true;
            }
            @Override
            public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) {

            }

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
                View itemView = viewHolder.itemView;
                ImageView delete_image=(ImageView) itemView.findViewById(R.id.delete_image);
                delete_image.setY(itemView.getTop());
                if(isCurrentlyActive) {
                    delete_image.setVisibility(View.VISIBLE);
                }else{
                    delete_image.setVisibility(View.GONE);
                }
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }

            @Override
            public int getMovementFlags(RecyclerView recyclerView,
                                        RecyclerView.ViewHolder viewHolder) {
                int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                return makeMovementFlags(dragFlags, swipeFlags);
            }
        };


ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
        itemTouchHelper.attachToRecyclerView(mRecyclerView);

Custom Layout for recylerview item

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"

    android:paddingBottom="@dimen/padding_xsmall">

    <LinearLayout
        android:id="@+id/top_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:background="@color/very_light_grey"
        android:orientation="horizontal"
        android:paddingBottom="@dimen/padding_xlarge"
        android:paddingEnd="@dimen/padding_small"
        android:paddingLeft="@dimen/padding_xlarge"
        android:paddingRight="@dimen/padding_small"
        android:paddingStart="@dimen/padding_xlarge"
        android:paddingTop="@dimen/padding_xlarge">

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/friend_image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical"
            fresco:placeholderImage="@drawable/user_placeholder"
            fresco:roundAsCircle="true"
            fresco:roundedCornerRadius="50dp"
            fresco:roundingBorderColor="@android:color/white"
            fresco:roundingBorderWidth="2dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginEnd="@dimen/margin_small"
            android:layout_marginLeft="@dimen/margin_small"
            android:layout_marginRight="@dimen/margin_small"
            android:layout_marginStart="@dimen/margin_small"
            android:orientation="vertical">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <bi.it.com.bio.textview.CustomTextView
                    android:id="@+id/friend_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentStart="true"
                    android:layout_toLeftOf="@+id/badge_text"
                    android:text="John"
                    android:textSize="@dimen/text_size_medium" />

                <bi.it.com.bio.textview.CustomTextView
                    android:id="@+id/badge_text"
                    android:layout_width="16dp"
                    android:layout_height="16dp"
                    android:layout_alignParentRight="true"
                    android:background="@drawable/badgeicon"
                    android:gravity="center"
                    android:text="24"
                    android:textColor="@android:color/white"
                    android:textSize="@dimen/text_size_xxsmall" />
            </RelativeLayout>

            <bi.it.com.bio.textview.CustomTextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="this is message from john"
                android:textSize="@dimen/text_size_xsmall" />

        </LinearLayout>

    </LinearLayout>

    <ImageView
        android:id="@+id/delete_image"
        android:paddingLeft="@dimen/padding_large"
        android:paddingStart="@dimen/padding_large"
        android:paddingEnd="@dimen/padding_large"
        android:paddingRight="@dimen/padding_large"
        android:paddingTop="@dimen/padding_small"
        android:paddingBottom="@dimen/padding_small"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/red_color_list"
        android:src="@drawable/ic_delete_frd"
        android:layout_gravity="end|right"
        android:visibility="gone"/>

</FrameLayout>

I do not want to use any library. Any help is really appreciated. Thanks in advance.

Aakash
  • 5,181
  • 5
  • 20
  • 37

2 Answers2

2

You can do this with a ViewPager and a PagerAdapter. Your PagerAdapter will have two pages: your "main" full-width view and a second view that has your operation buttons.

The key is to override getPageWidth() in your adapter and return 1.0 for your main view and some fraction for your second view. The fraction is calculated by dividing the desired width of the view by the width of the ViewPager.

When the user swipes, the second view can't take up the entire screen, so the first view is still partially shown, as in your animated image.

With the ViewHolder referencing the ViewPager and the ViewPager referencing the PagerAdapter, you can even recycle the adapters right along with the ViewPagers.

kris larson
  • 30,387
  • 5
  • 62
  • 74
  • With a 2K rep, you seem perfectly capable of coding that from the description, but in case you *do* you need help with the code, let me know. – kris larson Oct 22 '15 at 01:23
  • thanks i will try that for sure, but isn't there any simpler way than that? Also have you implemented using the method you mentioned. – Aakash Oct 22 '15 at 14:33
  • You mentioned that you weren't interested in using an external library, but that's probably the only thing that would be easier. I don't consider writing your own code with `onTouchEvent()` and `fling()` easier. If there was an easier non-library way to do it, someone else would have already provided an answer. I tested the partial paging aspect of the solution with some `ViewPager` demo code I had, so I know the behavior works. – kris larson Oct 22 '15 at 15:20
  • alright,can you share your code so that i can try it and save some time – Aakash Oct 23 '15 at 01:28
  • 2
    Wow, still figuring this one out. Finally got the `ViewPager` to show up (you have to designate a specific height for it, you can't use `wrap_content`), but now I am trying to get the swiped state of the `ViewPager` to persist and be recreated when the `ViewPager` is recycled. – kris larson Oct 26 '15 at 14:33
1

Actually there is a hidden useful class in the Android sdk called ViewDragHelper

You can implement the swipe to show button easily with little code. However, ViewDragHelper is not well documented, but I found this link contains a very useful tutorial for implementing it: http://fedepaol.github.io/blog/2014/09/01/dragging-with-viewdraghelper/

Chau Thai
  • 704
  • 6
  • 10