Use ItemTouchHelper for Swipe-To-Dismiss with another View displayed behind the swiped out

后端 未结 2 1140
北恋
北恋 2021-01-30 11:04

I have a RecyclerView and want to allow my users to use a swipe gesture to remove items from the list. But as known from other apps (e.g. Gmail), I want to show a delete icon be

相关标签:
2条回答
  • 2021-01-30 11:48

    I have done it with having the following layout structure for the recycler view item:

    <FrameLayout
        background = dark>
        <AnyLayout with content
           android:id="@+id/removable">
        </AnyLayout>
    <FrameLayout>
    

    Then I use this view holder as base view holder in my adapter:

    public class RemovableViewHolder extends RecyclerView.ViewHolder {
        private View mRemoveableView;
    
        public RemovableViewHolder(final View itemView) {
            super(itemView);
    
            mRemoveableView = itemView.findViewById(R.id.removable);
        }
    
        public View getSwipableView() {
            return mRemoveableView;
        }
    }
    

    In my ItemTouchHelper.Callback class I extend the following methods like that:

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (viewHolder instanceof RemovableViewHolder) {
            int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
            return makeMovementFlags(0, swipeFlags);
        } else
            return 0;
    }
    
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        getDefaultUIUtil().clearView(((RemovableViewHolder) viewHolder).getSwipableView());
    }
    
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (viewHolder != null) {
            getDefaultUIUtil().onSelected(((RemovableViewHolder) viewHolder).getSwipableView());
        }
    }
    
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        getDefaultUIUtil().onDraw(c, recyclerView, ((RemovableViewHolder) viewHolder).getSwipableView(), dX, dY,    actionState, isCurrentlyActive);
    }
    
    public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        getDefaultUIUtil().onDrawOver(c, recyclerView, ((RemovableViewHolder) viewHolder).getSwipableView(), dX, dY,    actionState, isCurrentlyActive);
    }
    

    With this approach you use one level in layouts more, but saves yourself troubles with drawing on Canvas. Also you may select other views inside the item, for example save one that was touched and return it and have children of an item also swipeable.

    Attaching to the recycler view:

    final ItemTouchHelper.Callback callback = new RemovableItemTouchHelperCallback(mAdapter);
    final ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(recyclerView)
    
    0 讨论(0)
  • 2021-01-30 12:07

    use the onChildDraw() method from ItemTouchHelper - I have it working with a bitmap and coloured background for swiping left and right with different colors and icons:

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    
                if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
    
                    View itemView = viewHolder.itemView;
    
                    Paint paint = new Paint();
                    Bitmap bitmap;
    
                    if (dX > 0) { // swiping right
                        paint.setColor(getResources().getColor(R.color.child_view_complete));
                        bitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_circle_complete);
                        float height = (itemView.getHeight() / 2) - (bitmap.getHeight() / 2);
    
                        c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX, (float) itemView.getBottom(), paint);
                        c.drawBitmap(bitmap, 96f, (float) itemView.getTop() + height, null);
    
                    } else { // swiping left
                        paint.setColor(getResources().getColor(R.color.primaryColorAccent));
                        bitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_circle_bin);
                        float height = (itemView.getHeight() / 2) - (bitmap.getHeight() / 2);
                        float bitmapWidth = bitmap.getWidth();
    
                        c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom(), paint);
                        c.drawBitmap(bitmap, ((float) itemView.getRight() - bitmapWidth) - 96f, (float) itemView.getTop() + height, null);
                    }
    
                    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    
    
                }
            }
    

    96f can be replaced with whatever distance from the left/right side you'd like it to be. This isn't perfect as when I'm down to 2 items in the adapter and I remove a position the canvas does not disappear and remains until the adapter is set again - working on trying to resolve now - I'll update if I find a complete solution but for now this is what I think you're looking for.

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