RecyclerView Swipe avec une vue en dessous de lui

j'ai fait quelques recherches et je n'ai pas encore trouvé un exemple ou une implémentation qui vous permette de mettre une vue (Image D'exemple ci-dessous) sous le RecyclerView quand vous glissez. Est-ce que quelqu'un a un exemple ou une idée de la façon dont cela serait mis en œuvre sans utiliser une bibliothèque.

Voici comment je suis en train de mettre en œuvre le coup à rejeter.

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 int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return super.getSwipeDirs(recyclerView, viewHolder);
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        if (viewHolder instanceof ViewDividers) {
            Log.e("DIRECTION", direction + "");
        }
    }
};
new ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recycler);

Voici l'exemple de la boîte de réception de Google: enter image description here

44
demandé sur Eugene H 2015-08-26 16:05:40

5 réponses

ma compréhension de la façon dont cela est fait est que l'on mettrait deux vues dans le xml qui seraient affichées par ligne dans votre recyclerview.

alors par exemple, ce serait mon adaptateur:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public static class ExampleViewHolder extends RecyclerView.ViewHolder {
        public TextView background;
        public TextView foreground;

        public ExampleViewHolder(View v) {
            super(v);
            background = (TextView) v.findViewById(R.id.background);
            foreground = (TextView) v.findViewById(R.id.foreground);
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
            if (holder instanceof ExampleViewHolder) {
                ((ExampleViewHolder) holder).background.setBackgroundColor(); // do your manipulation of background and foreground here.
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                          int viewType) {

            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.example, parent, false);
            return new ExampleViewHolder(v);
        }


    }
}

chaque ligne de recyclerview tire la mise en page xml de R. layout.exemple. Par conséquent, pour créer une vue en dessous, vous pouvez juste utiliser relativelayout ou framelayout pour créer les vues les uns sur les autres:

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/background"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/foreground"/>
</RelativeLayout>

Alors si vous ne voulez pas utiliser un bibliothèque pour le balayage, vous pouvez copier cette classe à partir de google et ensuite modifié par Bruno Romeu Nunes:

https://github.com/heruoxin/Clip-Stack/blob/master/app/src/main/java/com/catchingnow/tinyclipboardmanager/SwipeableRecyclerViewTouchListener.java

La classe va vous demander de créer un balayage auditeur:

swipeTouchListener =
        new SwipeableRecyclerViewTouchListener(mRecyclerView,
                new SwipeableRecyclerViewTouchListener.SwipeListener() {
                    @Override
                    public boolean canSwipe(int position) {
                        if (position == totalPost.size() - 1 && !connected) {
                            return false;
                        }
                        return true;
                    }

                    @Override
                    public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            //change some data if you swipe left
                        }
                        myAdapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
                        for (int position : reverseSortedPositions) {
                            //change some data if you swipe right
                        }
                        myAdapter.notifyDataSetChanged();
                    }
                });

alors liez simplement avec votre recyclerview:

    mRecyclerView.addOnItemTouchListener(swipeTouchListener);
21
répondu Simon 2015-08-28 15:27:01

j'enquêtais sur la même question.

Ce que j'ai fini par faire était, dans la mise en page qui contenait le recyclerView, j'ai ajouté un simple FrameLayout appelé "swipe_bg" de la même hauteur que l'un de mes RecyclerView.ViewHolder éléments. J'ai placé sa visibilité à "parti", et je l'ai placée sous le RecyclerView

puis dans mon activité où je mets le ItemTouchHelper, je remplace la onChildDraw comme si..

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);
    }
};

Je ne sais pas si c'est la meilleure façon, mais ça m'a semblé la plus simple.

9
répondu erik 2017-09-26 12:10:44

j'aime l'approche @erik mais je recommande de dessiner ce que vous voulez via la fonction Canvas passé à onChildDraw (). par exemple, un élément en arrière-plan ou une icône.

@Override 
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    final ColorDrawable background = new ColorDrawable(Color.RED);
    background.setBounds(0, itemView.getTop(),   itemView.getLeft() + dX, itemView.getBottom());
    background.draw(c);

    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}

dans cette approche, vous tirerez ce qui est nécessaire sur demande et pas besoin de gonfler les vues inutilisées

4
répondu Ali Mehrpour 2016-10-17 16:35:39

solution Simple sans répartition ou dessin sur toile. SomeAdapter.SomeVH devrait contenir la vue supérieure et la vue inférieure. Et avec cette approche nous serons en mesure de glisser seulement la vue supérieure (conteneur), en exposant sous la vue (avec étiquette, icône ce que vous voulez)

class SomeTouchHelper extends ItemTouchHelper.Callback {
...
    @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) {
            if (viewHolder instanceof SomeAdapter.SomeVH) {
                SomeAdapter.SomeVH someViewHolder
                        = (SomeAdapter.SomeVH) viewHolder;
                ViewCompat.setTranslationX(someViewHolder.mContainer, dX);
            }
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }
...
}

n'oubliez pas de restaurer l'état de vue initial de SomeVH en Adaptateur onViewRecycled ()

1
répondu Yazazzello 2017-08-16 15:28:21

Vous pouvez utiliser RvTools Bibliothèque. Il vous aidera à mettre en application facilement ce que vous voulez.

il suffit de créer votre SwipeContextMenuDrawer avec le regard désiré

public class YourSwipeContextMenuDrawer extends SwipeContextMenuDrawer {

private final Paint mRightPaint;
private final Paint mIconPaint;
private final Bitmap mRightIconBitmap;

public YourSwipeContextMenuDrawer(@NonNull Context context) {
    mRightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mRightPaint.setColor(ContextCompat.getColor(context, R.color.deep_orange_400));
    mRightIconBitmap = GraphicUtils.getBitmap(context, R.drawable.ic_delete, 100, 100);
    mIconPaint = new Paint();
    mIconPaint.setColorFilter(new PorterDuffColorFilter(ContextCompat.getColor(context, R.color.backgroundColor), PorterDuff.Mode.SRC_IN));
}

@Override
public void drawRight(@NonNull Canvas canvas, @NonNull View view) {
    canvas.drawRect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), mRightPaint);
    canvas.drawBitmap(mRightIconBitmap, view.getLeft() + mRightIconBitmap.getWidth() - 20, (view.getBottom() + view.getTop() - mRightIconBitmap.getHeight()) >> 1, mIconPaint);
}

@Override
public void drawLeft(@NonNull Canvas canvas, @NonNull View view) {
}
}

Et créer RvTools exemple avec l'action de balayage et balayez vers le menu contextuel de ce tiroir

 new RvTools.Builder(recyclerView)
            .withSwipeRightAction(this)
            .withSwipeContextMenuDrawer(new YourSwipeContextMenuDrawer(getContext()))
            .buildAndApplyToRecyclerView();
0
répondu Olexii Muraviov 2017-03-09 18:06:24