Showing custom View under swiped RecyclerView item

后端 未结 5 1054
独厮守ぢ
独厮守ぢ 2020-12-24 08:55

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

相关标签:
5条回答
  • 2020-12-24 09:24

    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>
    
    0 讨论(0)
  • 2020-12-24 09:28

    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.

    0 讨论(0)
  • 2020-12-24 09:41

    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

    0 讨论(0)
  • 2020-12-24 09:42

    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

    0 讨论(0)
  • 2020-12-24 09:44

    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.

    0 讨论(0)
提交回复
热议问题