android - recyclerview - oncreateviewholder que es
RecyclerView Desliza con una vista debajo de él (5)
He estado investigando un poco y aún tengo que encontrar un ejemplo o implementación que le permita poner una vista (Imagen de ejemplo a continuación) debajo de RecyclerView cuando desliza. ¿Alguien tiene algún ejemplo o una idea de cómo esto se implementaría SIN usar una biblioteca?
Así es como estoy implementando el deslizamiento para descartar.
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);
Estaba investigando el mismo problema.
Lo que terminé haciendo fue, en el diseño que contenía el recyclerView, agregué un FrameLayout
simple llamado ''swipe_bg'' de la misma altura que uno de mis elementos RecyclerView.ViewHolder
. Configuré su visibilidad como "ida" y la coloqué debajo de RecyclerView
Luego, en mi actividad donde configuro el ItemTouchHelper
, anulo el onChildDraw como tal ...
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);
}
};
No sé si esa es la mejor manera, pero me pareció la forma más sencilla.
Me gusta el enfoque @erik, pero recomendaría dibujar lo que quiera a través de la función canvas aprobada en onChildDraw (). por ejemplo, fondo o ícono del artículo.
@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);
}
En este enfoque, dibujará lo que necesite bajo demanda y no será necesario inflar las vistas no utilizadas
Mi comprensión de cómo se hace esto es que uno pondría dos vistas en el xml que se mostraría por línea en su vista de reciclador.
Entonces, por ejemplo, este sería mi adaptador:
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);
}
}
}
Cada línea en la vista de reciclador está extrayendo el diseño xml de R.layout.example. Por lo tanto, para crear una vista debajo, puede usar relativelayout o framelayout para crear las vistas una encima de la otra:
<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>
Entonces, si no quiere usar una biblioteca para deslizar, puede copiar esta clase de google y posteriormente la modifica Bruno Romeu Nunes:
La clase requerirá que crees un oyente de deslizamiento:
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();
}
});
Luego simplemente conéctelo con su vista de reciclador:
mRecyclerView.addOnItemTouchListener(swipeTouchListener);
Puede usar la Biblioteca de RvTools . Le ayudará a implementar fácilmente lo que desea.
Simplemente crea tu SwipeContextMenuDrawer con el aspecto deseado
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) {
}
}
Y crea una instancia de RvTools con la acción de deslizar y desliza el menú contextual del menú como este
new RvTools.Builder(recyclerView)
.withSwipeRightAction(this)
.withSwipeContextMenuDrawer(new YourSwipeContextMenuDrawer(getContext()))
.buildAndApplyToRecyclerView();
Solución simple sin asignación o dibujo en lienzo. SomeAdapter.SomeVH
debe contener vista superior y vista inferior. Y con este enfoque, podremos deslizar solo la vista superior (contenedor), exponiendo debajo de la vista (con la etiqueta, el icono, lo que quieras)
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);
}
}
...
}
no olvide restaurar el estado de vista inicial de SomeVH
en el adaptador en ViewRecycled ()